当然也可以直接用开发板搞起,不过我就这么一个,舍不得。
之前一直有人问这体验板和开发板有什么不同,这要我怎么回答。。。长得不同呗,其实这两主要部分就是一个玩意;不过使用开发板上面的模块需要买个降压模块,3.3V的,电路上出来的是5V,不能直接用,如果是体验板就不要了,直接用。如果有的朋友比较浪,直接一个开发板搭上去,我也无话可说了,跟体验板一样,直接使用就好了。
1.2硬件搭建
啥也不说,把灭蚊器拆开看一下;
看一下电路部分吧;
恩,好简单的玩意,就是点个灯转个风扇的事,啥也不说了,直接把电路搭好吧;
可能大家看电路图容易理解一点,好吧,我花几分钟画个简单的原理图;
可以看到,原理其实很简单,就是把电源引出到继电器上面,然后让体验板能够直接控制电源的通断,说的再直白一点,就是给产品引出一个新的开关,只不过这个开关我能使用软件控制而已。
最后来一张做完的图片,里面都看不到了,跟买来的时候一模一样,但是却能让我自由控制了;
这就是基本的硬件结构了,下面介绍软件的处理。
1.3 ESP8266固件编写
首先确定一下我需要什么功能:
1.定时开关设备,健忘症必备,少不了的东西;
2.局域网控制,虽然是在家里,走两步就可以了,但是我比较懒,有时候在床上,懒得动;
3.开关状态反馈,**作之前好歹要知道现在设备是工作还是休息的吧,少不了;
4.微信控制,反正有现成的东西,不要我白不要,搞起;
5.APP控制,我是不太喜欢微信点来点去的,做个APP,果断直接,必须支持广域网,局域网随便了,反正网上那么多UDP/TCP的APP,看心情吧;
6.上位机控制,我的老本行,少不了,局域网和广域网都要做,作为一个程序员,离不开电脑,手机我还没那么依赖;
7.一键配置网络肯定不能少,恩,airkiss和smartconfig少不了;
差不多就这些了,现在可以搞起了。图个快捷简单,直接在开发快源码上做手脚。
1.3.1 IO口的驱动
避免冲突,找个开发板没使用的IO口来搞事情,就GPIO8了,没有为什么。改代码其实蛮简单了,就把一些不要的函数直接干掉,加上自己的就好了;
先做个无关紧要的事情,改下版本号:
#define SOFTWARE_VERSION "小白-电子灭蚊器源码"
第一个函数:本来是获取工作模式的,**作个继电器而已,不需要那么多东西,直接删掉,使用WORK_MODE_RGB模式
user_get_work_mode(et_uint32 *mode)
{
*mode = WORK_MODE_RGB;
return RETURN_OK;
}
第二个函数:user_init_work_mode(et_uint32 mode, et_uchar fac_norm_mode)
虽然原本函数删了再说;
user_init_work_mode(et_uint32 mode, et_uchar fac_norm_mode)
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U,FUNC_GPIO12);
return RETURN_OK;
}
看过我之前的文章的朋友都知道,我习惯一边写代码,一边写文档;所以里面会有一些测试的东西,大家忽略不计,我做了注释;
初始化就这么完了,定义一下对GPIO的操作;
/*开关继电器的操作*/
#define my_gpio GPIO_INPUT_GET(GPIO_ID_PIN(8))
#define MY_ON GPIO_OUTPUT_SET(GPIO_ID_PIN(8), 1)
#define MY_OFF GPIO_OUTPUT_SET(GPIO_ID_PIN(8), 0)
这里我要处理下串口的内容,做个数据透传,不然我数据发没发,发了些啥玩意都不知道,官方源码里面有现成的,不过我用的不是很顺手,改一下,反正我自己写过;
/********************************************
* 函数名:uart0_tx_buffer(uint8 *buf, uint16 len)
* 函数用途:发送数组
* 参数1:buf
* 参数1作用:数组指针
* 参数1:len
* 参数1作用:数组长度
* 修改时间:2017-1-14
* 修改人:小白
********************************************/
void ICACHE_FLASH_ATTR
uart0_tx_buffer(uint8 *buf, uint16 len)
{
uint16 i;
for (i = 0; i < len; i++)
{
uart_tx_one_char(UART0, buf);
}
}
/********************************************
* 函数名:uart0_tx_SendStr(uint8 *buf)
* 函数用途:发送字符串
* 参数:buf
* 参数作用:数组指针
* 修改时间:2017-1-14
* 修改人:小白
********************************************/
void ICACHE_FLASH_ATTR
uart0_tx_SendStr(uint8 *buf)
{
while(*buf!='\0')
{
uart0_tx_buffer(buf++,1);
}
}
/********************************************
* 函数名:uart0_tx_SendNum(uint32 num)
* 函数用途:发送整型数
* 参数:num
* 参数作用:要发送的数
* 修改时间:2017-1-14
* 修改人:小白
********************************************/
void ICACHE_FLASH_ATTR
uart0_tx_SendNum(uint32 num)
{
uint8 buf[10];
uint32 numTmp = num;
int8 i=0;
while(numTmp)
{
numTmp=numTmp/10;
i++;
}
buf[i--]='\0';
for(;i>=0;i--)
{
buf=num%10 + '0';
num/=10;
}
uart0_tx_SendStr(buf);
}
这一段大家看不明白可以看我的学习笔记串口发送的内容,或者干脆别理,反正跟正常功能不挂钩,至于串口调试怎么做的,我就不说了,直接上ILINK远程控制的代码,这一部分是通用的,手机、上位机、微信远程控制都是这一段控制代码,很简单的if判断;
对ILINK接收回调函数的处理,这里面东西蛮多不要的,删了删了~~~,然后改一下,具体的我就不说了,上源码。目的是实现微信、app、上位机的远程控制.
et_int32 parse_msg_from_mqtt(et_uchar *msg_buf, et_int32 data_len)
{
et_int32 i, pos=0, rc = -1;
et_uchar cmd, type, bcc;
et_int32 len, seq;
et_uint16 gb_code=0;
WORK_MODE_T mode;
os_printf("\r\n数据内容:\r\n");
uart0_tx_SendStr(msg_buf);
char *my_OFF="OFF";
char *my_ON="ON";
if(strcmp(msg_buf,my_OFF)==0) MY_OFF;
else if(strcmp(msg_buf,my_ON)==0) MY_ON;
else
{
if(msg_buf[pos] != 0xFF ||msg_buf[pos + 1] != 0xFF)
{
os_printf("parse packet head error\n");
return rc;
}
pos += 2;
len = (msg_buf[pos] << 8) | msg_buf[pos + 1];
if(len < 3 || len != data_len - 2 - 2)
{
os_printf("parse packet length error\n");
return rc;
}
bcc = check_sum(&msg_buf[pos], len + 2 - 1);
if(bcc != msg_buf[data_len - 1])
{
msg.len = ack_to_mqtt(msg_buf, msg.buf, ACK_BCC_ERROR);
os_printf("bcc error\n");
rc = et_chat_to(g_cloud_handle,msg.buf, msg.len, g_user_id, SEND_TO_ALL);
return rc;
}
pos += 2;
cmd = msg_buf[pos];
pos += 1;
seq += msg_buf[pos];
pos += 1;
type = msg_buf[pos];
pos += 1;
mode = user_get_run_mode(); //get board mode from adc
switch(cmd)
{
case CMD_CONTROL:
{
switch(type)
{
case TYPE_RGB_LIGHT_DEV:
{
if(mode == WORK_MODE_RGB)
{ //code undefine
et_uchar red;
et_uchar gre;
et_uchar blu;
red = msg_buf[pos];
pos += 1;
gre = msg_buf[pos];
pos += 1;
blu = msg_buf[pos];
if(red==0&&gre==0&&blu==0)
{
MY_ON ;
}
else{
MY_OFF ;
}
RGB_light_set_color(red, gre, blu); //set rgb color
msg.len = ack_to_mqtt(msg_buf, msg.buf, ACK_SUCCESS);
rc = msg.len;
}
else
{
printf("mode error, mode = %u\n", mode);
msg.len = ack_to_mqtt(msg_buf, msg.buf, ACK_MODE_ERR);
rc = msg.len;
}
}
break;
default:
break;
}
}
break;
default:
msg.len = ack_to_mqtt(msg_buf, msg.buf, ACK_CMD_ILLIGAL);
rc = msg.len;
break;
}
}
bzero(msg_buf,sizeof(msg_buf));
// rc = et_chat_to(g_cloud_handle,msg.buf, msg.len, g_user_id, SEND_TO_CLOUD_FIRST);
return rc;
}
好像还是蛮多,稍微说两句,不想看的朋友跳过吧,这里首先判断是不是我自己定义的操作OFF/ON。是的话,就操作继电器,不是的话,就判断是不是微信来的数据,不是的话就啥也不干,是的话就操作继电器,思路还是蛮简单的吧。
这里提供官方的局域网传输控制代码,没做什么改动,就是在这个函数里面加上判断函数,就可以了:
#include "driver/gpio.h"
/*开关继电器的操作*/
#define my_gpio GPIO_INPUT_GET(GPIO_ID_PIN(12))
#define MY_ON GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 1)
#define MY_OFF GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 0)
extern et_cloud_handle g_cloud_handle;
et_int32 et_socket_recv_from(et_socket_t socket, et_uint8 *recv_buf, et_uint32 buf_len, et_addr_info_t *remote_info,
et_uint32 time_out_ms)
{
et_int32 rc;
struct sockaddr_in addr;
et_int32 addr_len = sizeof(struct sockaddr_in);
fd_set read_set;
struct timeval timer = {0, 0};
time_out_ms = 200;
timer.tv_sec = time_out_ms/1000;
timer.tv_usec = time_out_ms%1000*1000;
FD_ZERO(&read_set);
FD_SET(socket, &read_set);
if((rc = select(socket+1, &read_set, NULL, NULL, &timer)) > 0)
{
rc = recvfrom(socket, recv_buf, buf_len, 0, (struct sockaddr*)&addr,&addr_len);
et_strncpy(remote_info->ip_str, inet_ntoa(addr.sin_addr.s_addr), sizeof(remote_info->ip_str));
remote_info->port = ntohs(addr.sin_port);
printf("broadcast 0x%x:0x%x\n", addr.sin_addr.s_addr, addr.sin_port);
uart0_tx_SendStr(recv_buf);
char *my_OFF="OFF";
char *my_ON="ON";
char *my_get="GET";
if(strcmp(recv_buf,my_OFF)==0)
{
MY_OFF;
rc = et_chat_to(g_cloud_handle,"设备正在运行", 10, 0, SEND_TO_LOCAL);
}
else if(strcmp(recv_buf,my_ON)==0)
{
MY_ON;
rc = et_chat_to(g_cloud_handle,"设备已经关闭", 10, 0, SEND_TO_LOCAL);
}
else if(strcmp(recv_buf,my_get)==0)
{
if(my_gpio==0)
rc = et_chat_to(g_cloud_handle,"设备正在运行", 10, 0, SEND_TO_LOCAL);
else if(my_gpio==1)
rc = et_chat_to(g_cloud_handle,"设备已经关闭", 10, 0, SEND_TO_LOCAL);
}
}
else if(rc < 0 && !(errno == 0 || errno == EINTR || errno == EAGAIN || errno == EINPROGRESS || errno == EWOULDBLOCK)) ///< Socket error
{
printf("recv from failed\n");
return ET_FAILURE;
}
bzero(recv_buf,sizeof(recv_buf));
return rc;
}
#define ET_LISTEN_PORT_UDP_BROAD 2073 ///< UDP广播端口
当然也可以用自己的,如下:
if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0)
{
os_printf("got ip !!! \r\n");
InterNet_InitUDP("192.168.31.225",8888,8033);
if (user_main_start_flag == 0)
{
user_main_start_flag = 1;
xTaskCreate(et_user_main, "et_user_main", 1024, NULL, 2, NULL);
}
wifi_reconnect_start_flag = 1;
}
static void ICACHE_FLASH_ATTR
InterNet_Receive(void *arg, char *pdata, unsigned short len)
{
char *my_OFF="OFF";
char *my_ON="ON";
char *my_get="GET";
if(strcmp(pdata,my_OFF)==0)
{
MY_OFF;
InterNet_UDP_SendData("192.168.31.199", 8266,"开关已打开",10);
}
else if(strcmp(pdata,my_ON)==0)
{
MY_ON;
InterNet_UDP_SendData("192.168.31.199", 8266,"开关已关闭",10);
}
else if(strcmp(pdata,my_get)==0)
{
if(my_gpio==0)
InterNet_UDP_SendData("192.168.31.199", 8266,"OFF",3);
else if(my_gpio==1)
InterNet_UDP_SendData("192.168.31.199", 8266,"ON",2);
}
}
那么esp这边的代码就可以了,剩下的就是手机APP和上位机软件的设计了,大家可以直接下我的这个代码做测试,使用步骤如下:
1.首先下载一下固件:关于环境搭建,大家可以参考我之前的内容或者在官网找一下:
这里说个小技巧,打英文是不是很烦,大家可以使用tab键,直接自动补全。
成功编译了,更新固件就好了;
注意:不知道大家有没有遇到过这个情况,不管怎么样都进入不了工厂模式;我后来发现是我把flash size选错了,尴尬癌都有了;
考虑到是作为一个实际的制作,我把代码更新的具体步骤写一下,如果大家感觉说的不清楚,可以去官网找官方的烧录步骤,一样的,或者QQ群留言我也行,随意啦,搞过一两次,以后都是分分钟的事情了。
1.首先是保证板子有个正确的UID/APPKEY,这里可以使用fac.bin文件,我的附件里面提供了这些文件;
时间是2017/2/22,,防止大家搞错,我把Bin文件拿出来改了个名字叫电子灭蚊器,下图是大家可能用到的 所有文件。
虽然有几个固件可以不要,但是也还是下载一次,反正不费事;
下载完了,用串口打印,看一下是不是正常进入工厂模式;
可能不清楚,最后那个字符串是:
run in factory mode
有这个字符串就对了,因为我刷了工厂模式,然后刷UID/APPKEY。
1.使用开发快提供的UID烧写软件,把自己的UID什么的烧进去,我就不涂掉这里面的UID/APPKEY信息了,方便大家理解,大家最好用自己的UID/APPKEY信息,这是相当于你的QQ账号和密码的东西,我反正是DIY玩家,告诉你们也无所谓,各位自己搞还是不要泄露这个信息的好;
先连接好串口,然后输入自己的信息;
这种软件使用应该是蛮简单的,之前有个事情,就是好多朋友连接微信的时候,或者输入UID的时候,填的100;这是错误的,正确的UID是有34位的,大家可以看看我学习笔记的第六章第二节,或者官方论坛找UID烧录的帖子看看。
2.然后断电重启看串口打印的情况。
数据内容:
software version:小白-电子灭蚊器源码
run in normal mode
Local_port:8033ssid=2.4G鐨刉IFI锛堟瘮杈冨揩锛?
mode : sta(5c:cf:7f:d0:e2:cf)
add if0
f r0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 4
pm open phy_2,type:2 0 0
cnt
connected with 2.4G鐨刉IFI锛堟瘮杈冨揩锛? channel 3
dhcp client start...
et connect to ssid 2.4G鐨刉IFI锛堟瘮杈冨揩锛? channel 3
ip:192.168.31.225,mask:255.255.255.0,gw:192.168.31.1
got ip !!!
ET U-SDK var3.0.0.6
uid : Fc5wGsTuvumomVom6wSQTwUVj3eWa5oUQq
appkey : 4d66c9c0-8082-444637
secretkey : 3c2cd461698ed83099630174f5ddf340
server information lb.kaifakuai.com : 8085
Local Ip 192.168.31.225
You are connect:0x1
数据包括,现在已经连接上我的WIFI,显示这个代码的版本号,显示ESP8266在局域网的IP,显示主机的IP.....
1.4上位机测试
1.上位机也修改下,让它按个按键就能控制我的设备。不做太细致的优化,只实现需要的功能;
打开我的上位机(广域网通信的设置)
图片对应信息:
1.ESP上面的UID信息
2.进开发快申请一个自己的UID/APPKEY
3.登录
登录成功如下所示:此时可以对体验版进行远程控制(广域网);
2.局域网设置