前言:    
从接触ESP8266到现在有一段时间了,也感受到ESP8266的强大,其高性价比给极客者们带来了极大的福音。之前用ESP8266改装了一部遥控车,使其能用手机控制,手机app是用易安卓编制的,遥控车视频挂到b站了,视频地址:
https://www.bilibili.com/video/av20141857?from=search&seid=10781143291446850224
<https://www.bilibili.com/video/av20141857?from=search&seid=10781143291446850224>
   
这次是打算用Arduino+ESP8266来实现智能配网以及通过EDP协议上传温度、湿度和光照强度等数据到OneNET平台,也可以用EDP下发命令来实现远程控制。
所需材料:    Arduino_pro_mini         1    ESP8266-12F              1     USB-TTL
串口下载模块       1    DHT11温湿度传感器        1    面包板及杜板线           若干    光敏电阻       
         1    电阻及发光二极管等       若干
智能配网(Smart Config)SmartConfig的过程:    1、wifi模块通电,没有可用的wifi, 进入混杂模式,
开始监(和谐)听覆盖范围内所有WiFi数据帧;
    2、手机APP或微信端发送包含WIFI用户名和WIFI密码的UDP广播包或者组播包;
    3、智能终端的WIFI芯片可以接收到该UDP包,只要知道UDP的组织形式,就可以通过接收到的UDP包解密出WIFI用户名和密码;
    4、然后智能硬件配置收到的WIFI用户名和密码到指定的WIFI AP(路由器)上。    
ESP8266可通过AT指令进入智能配网模式,我所用的AT固件是安信可推出的固件,可在安信可官网里
http://wiki.ai-thinker.com/esp8266/sdk <http://wiki.ai-thinker.com/esp8266/sdk>
下载。配网的AT指令可参考安信可官网http://wiki.ai-thinker.com/esp8266/examples/at_demo
<http://wiki.ai-thinker.com/esp8266/examples/at_demo>里的步骤。通过将AT指令写在pro
mini内,再通过外部按钮按下进入配网。    pro mini通过软串口跟ESP8266通信,而ESP8266用的是3.3V电源,pro
mini用的是5V电源,所以串口必须通过电平转换才行,由于身边暂时没有电平转换模块,所以只能通过分压来实现。经过实测,ESP8266跟pro
mini软串口通信用115200波特率会出现乱码,所以只能用9600波特率。    分压和配网按钮接线图如下所示:
 程序如下:#include<SoftwareSerial.h> //使用软串口的库文件 #define configkey 2 //配网按钮,按住时候配网
#define configRED 7 //智能配网失败红灯亮起 #define configGREEN 8 //智能配网成功绿灯亮起 #define
TcpLED 12 //OneNET的TCP连接灯 #define EdpLED 6 //OneNET的EDP连接灯 bool link;
//判断智能配网是否成功 bool keyOK=1; //判断配网按钮是否可用 SoftwareSerial mySerial(10, 9); // RX,
TX void setup() { mySerial.begin(9600); pinMode(configkey,INPUT); //设置按键引脚为输入
pinMode(configRED,OUTPUT); //没连上无线网 pinMode(configGREEN,OUTPUT); //连上无线网
pinMode(TcpLED,OUTPUT); //连上OneNET的TCP pinMode(EdpLED,OUTPUT); //连上OneNET的EDP }
void loop() { int buttonState = digitalRead(configkey); if(buttonState==0 &&
keyOK==1){ //按钮被按下时     mySerial.print("+++");     delay(100);
    mySerial.print("+++");     delay(100);     digitalWrite(TcpLED, HIGH);
    analogWrite(EdpLED,255);     digitalWrite(configGREEN, HIGH);     
digitalWrite(configRED, HIGH);     while (!doCmdOk("AT+CWSTARTSMART=3",
"OK",5)); //启动智能配网     t1=0;     Serial.println("Smartconfig Start");
    digitalWrite(testLED, HIGH);     while (!doConfigOK("smartconfig connected
wifi"));     t1=0; if(link==1){ Serial.println("do Config OK");
digitalWrite(configGREEN, LOW); digitalWrite(testLED, LOW); while
(!doCmdOk("AT+CIPSTART=\"TCP\",\"183.230.40.39\",876","CONNECT",5));
//OneNET的TCP透传 t1=0; digitalWrite(TcpLED, LOW); //tcp连接指示灯亮 Serial.println("TCP
connect OK"); while (!doCmdOk("AT+CIPMODE=1", "OK",5)); //透传模式 t1=0; while
(!doCmdOk("AT+CIPSEND", ">",5)); //开始发送 t1=0; link=1; edp_connect=0; keyOK=0;
Serial.println("Start send"); } else { Serial.println("do Config ERROR");
digitalWrite(configRED, LOW); digitalWrite(testLED, LOW); } while
(!doCmdOk("AT+CWSTOPSMART", "OK",5)); //不管ESP8266有没有连上wifi,都要释放内存 t1=0; }
等待串口命令结果函数booldoCmdOk(String data, char keyword[], int timeout){
//给ESP8266发送AT指令,在次数timeout范围内回应正确就返回TURE bool result = false; if (data != ""){
mySerial.println(data); //发送AT指令 Serial.print("SEND: "); Serial.println(data);
} while (!mySerial.available()); // 等待模块回复 delay(200); if
(mySerial.find(keyword)){ //返回值判断 Serial.println("do cmd OK"); response=1;
result = true; } else { Serial.println("do cmd ERROR"); result = false; }
while(mySerial.read()>= 0){} //清空串口接收缓存 delay(800); //指令时间间隔 t1++;
if(t1>=timeout){ //超过设定时间,跳出循环,并返回回应判断response的值 result = true; response=0; }
return result; }配网时等待串口回复函数booldoConfigOK(char keyword1[]){ //开启智能配网 bool
result1 = false; linktime=0; while (!mySerial.available()){ // 等待模块回复,10秒内要配网完成
t1++; delay(1000); if(t1 >= 10){ linktime=1; link=0; result1 = true;
Serial.println("Config timeout"); break; //超过时间串口没收到信号就跳出 } } if(linktime==0){
delay(200); if (mySerial.find(keyword1)){ //返回值判断 link=1; result1 = true; }
else { link=0; result1 = false; } while(mySerial.read()>= 0){} //清空串口接收缓存
delay(500); //指令时间间隔 } return result1; }EDP连接    通过OneNET官网的库文件edp.c,可以很简单的连接到
OneNET平台。当成功连接到平台时,会收到0x20 0x02 0x00 0x00,可以用这个信号来判断是否连接上。if(link==1){
//当wifi连接上后,执行下面程序 if (!edp_connect){ while(mySerial.read()>= 0){} //清空串口接收缓存
packetSend(packetConnect(ID, KEY)); //发送EPD连接包 while (!mySerial.available());
//等待EDP连接应答 delay(200); if ((tmp = mySerial.readBytes(rcv_pkt.data,
sizeof(rcv_pkt.data))) > 0 ){ rcvDebug(rcv_pkt.data, tmp); if (rcv_pkt.data[0]
== 0x20 && rcv_pkt.data[1] == 0x02 && rcv_pkt.data[2] == 0x00 &&
rcv_pkt.data[3] == 0x00) { edp_connect = 1; analogWrite(EdpLED,0);
Serial.println("EDP connected."); } else Serial.println("EDP connect error.");
} packetClear(&rcv_pkt); } }光敏电阻    光敏电阻通过分压,并通过模拟口A0输入到pro mini,接线电路图如下:    
通过分压后,读出的值在0~1024之间,数值越大,说明光线约弱,有点不太直观,于是我用个简单的函数将数值控制在0~100之间,并且数值越大,光线约强。
#define lightread A0 //光敏电阻读取的数值 ld_x=analogRead(lightread); //光敏电阻接收的信号,信号是模拟值
ld=(4490-4*ld_x)/49;温湿度传感器    温湿度传感器DHT11接线如下图所示:#include <dht11.h>
//使用DHT11的库文件 #define DHT11PIN A1 //DHT11温湿度模块数值 int wd;      //温度 int sd;     
//湿度 int chk = DHT11.read(DHT11PIN); //读DHT11 wd = (float)DHT11.temperature;
//获取温度 sd = (float)DHT11.humidity; //获取湿度上传数据到OneNET平台if (edp_connect &&
trigger){ Serial.print("temperature : "); Serial.println(wd); //串口打印温度
Serial.print("humidity : "); Serial.println(sd); //串口打印湿度
Serial.print("LigthRead_x : "); Serial.println(ld_x); //串口打印亮度(读值)
Serial.print("LigthRead_y : "); Serial.println(ld); //串口打印亮度(计算值)
Serial.println(" "); sprintf(wd1,"%d",wd); //int型转换char型 sprintf(sd1,"%d",sd);
//int型转换char型 sprintf(ld1,"%d",ld); //int型转换char型
packetSend(packetDataSaveTrans(NULL, "tem", wd1)); //发送的数据必须为字符串 delay(100);
packetSend(packetDataSaveTrans(NULL, "hum", sd1)); delay(100);
packetSend(packetDataSaveTrans(NULL, "light", ld1)); delay(2000); }EDP下发控制命令   
在OneNET平台开发者中心创建应用,在元件库里拉出一个开关按钮。按钮的EDP命令内容填datastr:{V}    接收EDP命令并解析的程序:
while(mySerial.available()){ readEdpPkt(&rcv_pkt); if (isEdpPkt(&rcv_pkt)){
pkt_type = rcv_pkt.data[0]; switch (pkt_type){ case CMDREQ: char
edp_command[50]; char edp_cmd_id[40]; long id_len, cmd_len, rm_len; char
datastr[20]; char val[10]; memset(edp_command, 0,sizeof(edp_command)); //置0
memset(edp_cmd_id, 0,sizeof(edp_cmd_id)); //置0
edpCommandReqParse(&rcv_pkt,edp_cmd_id, edp_command, &rm_len, &id_len,
&cmd_len); //按照EDP命令请求协议,解析数据 Serial.print("rm_len: "); Serial.println(rm_len,
DEC); delay(10); Serial.print("id_len: "); Serial.println(id_len, DEC);
delay(10); Serial.print("cmd_len: "); Serial.println(cmd_len, DEC); delay(10);
Serial.print("id: "); Serial.println(edp_cmd_id); delay(10); Serial.print("cmd:
"); Serial.println(edp_command); sscanf(edp_command,"%[^:]:%s", datastr, val);
if (atoi(val) == 1){ //atoi(),int转换为char,把一个整数转换为字符串。 Serial.println("LEDon");
// 使Led亮 digitalWrite(testLED, HIGH); } else if(atoi(val) == 0){
Serial.println("LEDoff"); // 使Led灭 digitalWrite(testLED, LOW); }
packetSend(packetDataSaveTrans(NULL,datastr,val)); //将新数据值上传至数据流 break;
default: Serial.print("unknown type:"); Serial.println(pkt_type, HEX); break; }
} }最后的接线图:电脑端界面:

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信