乐鑫ESP8266芯片是一块性价比非常高的WIFI模组,本篇文章里飘易以ESP8266-01S这款wifi模组来进行具体的说明。
8266-01S 是一款低成本、低功耗的,集成一件式配置,P2P 远程协议栈的微小体的串口转 wifi 透传 模块。主要应用领域为智能家居,物联网,工业智能控制和医疗设备相关领域,还能用于 DIY 专业用户 市场,通过模块的封装,大大的降低了无线应用技术门槛,能够让用户很方便快捷的,将模块应用到自 己系统或者改造原有有线控制系统,借助超低功耗 wifi 模块,让物联网变得更加实际和生动, 并且提供手机一键配置 wifi 模块实现网络连接功能,无需负载的配置设计,并提供可编程接口和传感器 接口功能。成为理想的嵌入式低功耗 wifi 解决方案。
一种典型的应用场景图如下:
Arduino通电后自动连接WIFI网络,如果WIFI网络连接失败,则自动进入smartconfig一键配网流程;当因网络环境发生变化时,用户可以主动按下配网按钮,硬件也自动进入一键配网,重新设置wifi连接信息。
Arduino UNO
ESP8266-01S WIFI模组
按键
杜邦线若干
我们先看下ESP8266引脚说明:
序号 | 引脚名称 | I/O | 描述 | DC特性 | 备注 |
1 | UTXD | AT 串口发送输出 | 3.3V | 开机时禁止下拉 | |
2 | GND | 地 | |||
3 | CH_PD(EN) | 模块断电信号 | 3.3V | 1)高电平工作; 2)低电平模块供电关掉; | |
4 | GPIO2 | 预留,默认悬空 | 3.3V | 开机上电时必须为高电平,禁止硬件下拉;内部默认已拉高 | |
5 | GPIO16 | I | 复位信号(RESET) | 3.3V | 低电平复位,高电平工作(默认高); |
6 | GPIO0 | 模块状态灯/工作模式选择 | 3.3V | 1)默认WiFiStatus: WiFi工作状态指示灯控制信号; 2)工作模式选择: 上拉:FlashBoot,工作模式; 下拉:UARTDownload,下载模式(下载固件); | |
7 | VCC | I | 模块采用单电源供电,通过 1 个VCC 电源引脚供电,电压范围:3.0V-3.6V,电流>600mA | Vmax=3.6V Vmin=3.0V Vnorm=3.3V | 电源供电能力请大于600mA;否则可能会引起模块工作异常,或者无线性能不好。 |
8 | URXD | AT 串口发送输入 | 3.3V |
MCU和wifi的通用连接示意图:
如果连接Arduino的话,接线如下(正常工作模式):
WIFI模块 | Arduino |
3V3 | 3.3V |
EN | 3.3V |
GND | GND |
TX | 6(软串口) |
RX | 7(软串口) |
图中的CH_PD引脚就是EN脚。
如果是让wifi和usb转ttl串口设备连接的话,参考下图:
正常的乐鑫官方的AT固件:
AT+GMR AT version:1.3.0.0(Jul 14 2016 18:54:01) SDK version:2.0.0(656edbf) compile time:Jul 19 2016 18:44:44 OK
乐鑫的AT固件下载地址:https://www.espressif.com/zh-hans/support/download/at
如果希望支持mqtt,可以刷支持mqtt的固件:
AT+GMR AT version:1.4.0.0(May 5 2017 16:10:59) SDK version:2.1.0(116b762) Simkeim Technology Co.,Ltd MQTT:Jun 7 2017 14:33:18 OK
我们先看看刷了乐鑫自家的AT固件的wifi模组支持哪些AT指令:
基础AT指令
AT 测试 AT 启动
AT+RST 重启模块
AT+GMR 查看版本信息
AT+GSLP 进入deep-sleep 模式
ATE 开关回显功能(ATE0 : 关闭回显;ATE1 : 开启回显)
AT+RESTORE 恢复出厂设置
AT+UART UART 配置, [@deprecated]不建议使用
AT+UART_CUR UART 当前临时配置
AT+UART_DEF UART 默认配置,保存到 flash
AT+SLEEP 设置 sleep 模式
AT+RFPOWER 设置 RF TX Power 上限
AT+RFVDD 根据 VDD33 设置 RF TX Power
WIFI功能AT指令
AT+CWMODE 设置 WiFi 模式(sta/AP/sta+AP), [@deprecated] 不建议使用
AT+CWMODE_CUR 设置 WiFi 模式(sta/AP/sta+AP),不保存到 flash
AT+CWMODE_DEF 设置 WiFi 模式( sta/AP/sta+AP),保存到 flash
AT+CWJAP 连接 AP, [@deprecated] 不建议使用
AT+CWJAP_CUR 连接 AP,不保存到 flashAT+CWJAP_DEF 连接 AP,保存到 flash
AT+CWLAPOPT 设置 AT+CWLAP 指令扫描结果的属性
AT+CWLAP 扫描附近的 AP 信息
AT+CWQAP 与 AP 断开连接
AT+CWSAP 设置 ESP8266 softAP 配置, [@deprecated] 不建议使用
AT+CWSAP_CUR 设置 ESP8266 softAP 配置,不保存到 flash
AT+CWSAP_DEF 设置 ESP8266 softAP 配置,保存到 flash
AT+CWLIF 获取连接到 ESP8266 softAP 的 station 的信息
AT+CWDHCP 设置 DHCP, [@deprecated] 不建议使用
AT+CWDHCP_CUR 设置 DHCP,不保存到 flash
AT+CWDHCP_DEF 设置 DHCP,保存到 flash
AT+CWDHCPS_CUR 设置 ESP8266 soft-AP DHCP 分配的 IP 范围,不保存到 Flash
AT+CWDHCPS_DEF 设置 ESP8266 soft-AP DHCP 分配的 IP 范围,保存到 Flash
AT+CWAUTOCONN 设置上电时是否主动连接 AP
AT+CIPSTAMAC 设置 ESP8266 station 的 MAC 地址, [@deprecated] 不建议使用
AT+CIPSTAMAC_CUR 设置 ESP8266 station 的 MAC 地址,不保存到 flash
AT+CIPSTAMAC_DEF 设置 ESP8266 station 的 MAC 地址,保存到 flash
AT+CIPAPMAC 设置 ESP8266 softAP 的 MAC 地址, [@deprecated] 不建议使用
AT+CIPAPMAC_CUR 设置 ESP8266 softAP 的 MAC 地址,不保存到 flash
AT+CIPAPMAC_DEF 设置 ESP8266 softAP 的 MAC 地址,保存到 flash
AT+CIPSTA 设置 ESP8266 station 的 IP 地址, [@deprecated] 不建议使用
AT+CIPSTA_CUR 设置 ESP8266 station 的 IP 地址,不保存到 flash
AT+CIPSTA_DEF 设置 ESP8266 station 的 IP 地址,保存到 flash
AT+CIPAP 设置 ESP8266 softAP 的 IP 地址, [@deprecated] 不建议使用
AT+CIPAP_CUR 设置 ESP8266 softAP 的 IP 地址,不保存到 flash
AT+CIPAP_DEF 设置 ESP8266 softAP 的 IP 地址,保存到 flash
AT+CWSTARTSMART 开始 SmartConfig(一键配网)
AT+CWSTOPSMART 停止SmartConfig(一键配网)
AT+CWSTARTDISCOVER 开启可被局域网内的微信探测的模式
AT+CWSTOPDISCOVER 关闭可被局域网内的微信探测的模式
AT+ 设置 WPS 功能
AT+MDNS 设置 MDNS 功能
TCP/IP相关AT指令
AT+CIPSTATUS 查询网络连接信息
AT+CIPDOMAIN 域名解析功能
AT+CIPSTART 建立TCP 连接,UDP 传输或者 SSL 连接
AT+CIPSSLSIZE 设置 SSL buffer 大小;
AT+CIPSEND 发送数据
AT+CIPSENDEX 发送数据,达到设置长度,或者遇到字符“/0”,则发送数据
AT+CIPSENDBUF 数据写入 TCP 发包缓存
AT+CIPBUFRESET 重置计数(TCP 发包缓存)
AT+CIPBUFSTATUS 查询 TCP 发包缓存的状态
AT+CIPCHECKSEQ 查询写入 TCP 发包缓存的某包是否成功发送
AT+CIPCLOSE 关闭 TCP/UDP/SSL 传输
AT+CIFSR 查询本地 IP 地址
AT+CIPMUX 设置多连接模式
AT+CIPSERVER 设置 TCP 服务器
AT+CIPMODE 设置透传模式
AT+SAVETRANSLINK 保存透传连接到 flash
AT+CIPSTO 设置 ESP8266 作为 TCP 服务器时的超时时间
AT+CIUPDATE 通过 WiFi 升级软件
AT+PING PING 功能
AT+CIPDINFO 接收网络数据时,“+IPD” 是否提示对端 IP 和端口;
Arduino串口数据乱码问题:
由于ESP8266-01S这款模组出厂的默认波特率是115200,而我们arduino和wif模组进行串口通讯的时候一般使用软串口,arduino在使用软串口进行通信的时候,最高支持的波特率是57600,如果波特率高于57600,就会出现乱码或丢包,因此我们需要将wifi模组的波特率设定到 57600 ,避免乱码,执行下面的AT指令修改默认的波特率:
AT+UART_DEF=57600,8,1,0,0
官方说明:https://www.arduino.cc/en/Reference/SoftwareSerial
当开机或发送AT+RST重启指令时,为什么会出现一部分乱码,然后才是ready?
这是正常现象,由于一些最初的设计原因,在板子上电初始跑boot rom的一段log需要在74880的波特率下打印。跑到用户程序区后,波特率改为115200(或用户设置的9600)后可正常打印的。
Arduino引用软串口库
#include <SoftwareSerial.h> // 软串口 SoftwareSerial WIFISerial(6, 7); // RX, TX交叉接线 #define OK "OK" #define SENDOK "SEND OK" #define WIFIPIN 4 //配网按键,按住2秒配网 bool WIFIPINAvailable = true;// 配网按钮是否可用 bool wifiLinked = false;// WIFI是否连接上AP bool serverLinked = false;// 服务器是否连接 unsigned long lastTime;
初始化
void setup() { pinMode(WIFIPIN, INPUT); // 硬件串口 initialize serial for debugging Serial.begin(115200); while (!Serial) {} // 软串口 initialize serial for ESP module WIFISerial.begin(57600); // WIFISerial.println("AT+UART_DEF=57600,8,1,0,0");//解决乱码 // delay(1000); while (!WIFISerial) {} WIFISerial.listen();// 开始监听 Serial.println(F("---setup start---")); // 查询网络连接状态,等待wifi连网几秒 bool _link = false; int _i = 0; bgnwifi: for (int i = 0; i < 3; i++) { // STATUS 2:获得 IP ,3:已连接,4:断开连接,5:未连接到 WiFi if (doCMD(F("AT+CIPSTATUS"), F("STATUS:2|STATUS:3"), 3000)) { _link = true; break; } delay(1000); } if (!_link && _i == 0) { doCMD(F("AT+RST"), F("ready"), 3000);// 重启wifi模块 delay(4000);// 等待连接 _i++; goto bgnwifi; } if (!_link) { smartConfig();// 启动一键配网 }else { wifiLinked = true; } lastTime = millis(); Serial.println(F("---setup end---")); }
飘易封装的公共函数:
// 执行AT指令 // cmd AT指令,返回值包含flag则true(2个以|分割),timeout超时时间ms(200的整数倍) bool doCMD(String cmd, String flag, long timeout) { String str = ""; WIFISerial.println(cmd); //发送AT指令 delay(300); flag.toLowerCase();// 小写 // 限期时间 long deadline = millis() + timeout; while (millis() < deadline) { str = ""; while (WIFISerial.available()) { str += (char)WIFISerial.read(); delay(2); } if (str != "") { Serial.println(str);// 打印输出 str.toLowerCase();// 小写 // 判断 flag 是否需要切割,以 | 切割,逻辑或关系 String flag1 = "", flag2 = ""; int commaPosition = flag.indexOf('|'); if (commaPosition > -1) { flag1 = flag.substring(0, commaPosition); flag2 = flag.substring(commaPosition + 1, flag.length()); } if (flag1 != "" && flag2 != "") { if (str.indexOf(flag1) > -1 || str.indexOf(flag2) > -1 ) { return true; } } if (str.indexOf(flag) > -1) { return true; } } delay(100); } return false; } // 一键配网 smartconfig void smartConfig() { // 启动smartconfig之前,先停止一下,以避免上次未复位 doCMD(F("AT+CWSTOPSMART"), OK, 3000); // SmartConfig 仅支持在 ESP8266 单 station 模式下调用 if (!doCMD(F("AT+CWMODE_DEF=1"), OK, 3000)) {} // 上电自动连接AP if (!doCMD(F("AT+CWAUTOCONN=1"), OK, 3000)) {} // 启动smartconfig,支持ESP-Touch和Airkiss智能配网 // 在 SmartConfig 过程中请勿执行其他指令 Serial.println(F("~~ Start SmartConfig ~~")); bool res = doCMD(F("AT+CWSTARTSMART=3"), F("WIFI GOT IP"), 60000);// 60秒超时 if (res) { wifiLinked = true; Serial.println(F("SmartConfig OK")); } else { wifiLinked = false; Serial.println(F("SmartConfig Fail")); } doCMD(F("AT+CWSTOPSMART"), OK, 3000);// 无论配网是否成功,都释放快连所占的内存 } // 连接TCP服务器 bool connectTcp() { bool linkOk = true; //连接服务器 String s(F("AT+CIPSTART=\"TCP\",\"tcp.x.com\",9960"));// 字符串存入FLASH if (!doCMD(s, F("OK|CONNECTED"), 3000)) { linkOk = false; } if (linkOk) { // 登录,也是心跳包,1分钟内必须上报一次,如有其他定时上报,则可不使用本心跳包 s = F("{\"method\": \"update\",\"gatewayNo\": \"01\",\"userkey\": \"123\"}&^!");// 字符串存入FLASH doCMD("AT+CIPSEND=" + String(s.length()), ">", 3000); if (!doCMD(s, SENDOK, 3000)) { linkOk = false; } } if (!linkOk) { Serial.println(F("!!SERVER NOT CONNECTED!!")); } else { } serverLinked = linkOk; return linkOk; }
loop循环函数:
void loop() { String info = ""; // 定时上报给服务器 - TCP长连接 if (millis() - lastTime == 5000) { // 判断wifi是否连接上 if (!wifiLinked) { Serial.println(F("!!WIFI NOT CONNECTED!!")); } else { //连接TCP服务器 if (!serverLinked) { connectTcp();//连接TCP服务器 } else { // 上报传感器值 - 定时上报,可代替心跳包(1分钟内1次) String temp = String(random(10, 40));// 模拟温度 String humi = String(random(40, 90));// 模拟湿度 if (true) { String s1(F("{\"method\": \"upload\",\"data\":[{\"Name\":\"temp\",\"Value\":\""));// 字符串存入FLASH String s2(F("\"},{\"Name\":\"humi\",\"Value\":\""));// 字符串存入FLASH String s3(F("\"}]}&^!"));// 字符串存入FLASH info = s1 + temp + s2 + humi + s3; Serial.println(info); doCMD("AT+CIPSEND=" + String(info.length()), ">", 3000); if (!doCMD(info, SENDOK, 3000)) { serverLinked = false; } else { } } } } } // 恢复计时,云端限制提交频率不能低于20秒 if (millis() - lastTime >= 50000) { lastTime = millis(); } // 读取WIFI配网按钮是否接通 boolean val = digitalRead(WIFIPIN); if (val && WIFIPINAvailable) { WIFIPINAvailable = false; Serial.println(F("WIFIPIN pressed")); smartConfig();// 启动一键配网 WIFIPINAvailable = true; } // PC串口转发给wifi软串口 while (Serial.available()) { WIFISerial.write(Serial.read()); } // wifi软串口发送过来的信息 String str = ""; while (WIFISerial.available()) { str = str + (char)WIFISerial.read(); } if (str != "") { Serial.println(str); } }
上面代码执行的业务逻辑是:每50秒为一个循环,在每个循环的第5秒上报传感器的温度和湿度值给云端。当用户按下wifi配网按钮时,wifi模组进入一键配网流程重新设置wifi的ssid和密码信息。
ESP8266的配网是比较方便的,支持乐鑫ESP-Touch和微信Airkiss。
苹果手机可以在APP Store里搜索“ESP-TOUCH“下载乐鑫的APP,安卓手机在各大应用市场也可以搜索到;或者你也可以直接下载安信可提供的安装包:
安卓:https://wiki.ai-thinker.com/_media/esp8266/examples/at_demo/smartconfig/esptouch_v3.7.1.zip
苹果:https://wiki.ai-thinker.com/_media/esp8266/examples/at_demo/smartconfig/esptouch_ios_v0.3.4.3.ipa.7z
Github上的源码:https://github.com/espressifapp
有了这些,我们就很容易给wifi设备配置了,如果你开发了自己的APP,也可以方便的把ESP-TOUCH集成到自己的APP里面。
除了APP实现smartconfig外,ESP8266还支持微信的airkiss配网,这个连APP都不需要了,直接在微信里就可以实现配网啦。
1,AT+CWMODE_DEF=1 !!配置WiFi模组工作模式为单STA模式,并把配置保存在flash
2,AT+CWAUTOCONN=1 !!使能上电自动连接AP
3,AT+CWSTARTSMART=3 !!支持ESP-Touch和Airkiss智能配网
4,打开微信,关注微信公众号“安信可科技”,点击wifi配置,点击开始配置,输入密码,点击连接
此时串口软件里会返回:
smartconfig type:AIRKISS Smart get wifi info ssid:yourWIFI password:123456 WIFI CONNECTED WIFI GOT IP smartconfig connected wifi
5,AT+CWSTOPSMART !!无论配网是否成功,都需要释放快连所占的内存
6,AT+CIPSTATUS !!查询网络连接状态,返回
AT+CIPSTATUS STATUS:2
配网成功啦。
我们使用按键来控制WIFI配网是否启动,按键接通后判断按键电路中的电压,如果电压大于4.88V,就认为按键按下了,此时启动wifi模组的一键配网。我们在按键一端连接5V,一端连接arduion的4号数字口,再连接下拉电阻接到GND,电路图如下:
1、当云端通讯的发送过来的数据长度较长时,wifi串口接收的缓冲区信息被截断的问题
由于Arduino默认的软串口缓冲区大小为64字符,我们把他调大一倍
<base Arduino folder>\hardware\arduino\avr\libraries\SoftwareSerial\SoftwareSerial.h Change: #define _SS_MAX_RX_BUFF 64 // RX buffer size To: #define _SS_MAX_RX_BUFF 128 // RX buffer size
参考:https://internetofhomethings.com/homethings/?p=927
注意,缓冲区越大,全局变量RAM会占用越多,不建议改太大,RAM一共才2KB,够用就好!
2、串口并行冲突问题
当wifi串口正在执行AT指令的过程中,云端下发控制指令会失败,因为wifi模组正在 busy s... 或 busy p...,此时,wifi模组无法正常处理。
3、Arduino编译的时候提示RAM不够的解决方法:
项目使用了 16480 字节,占用了 (51%) 程序存储空间。最大为 32256 字节。 全局变量使用了1375字节,(67%)的动态内存,余留673字节局部变量。最大为2048字节。
一:F宏函数,存入FLASH里:Serial.println(F("---setup start---"));
二:利用PROGMEM,存入FLASH里
https://blog.csdn.net/u012388993/article/details/60868550
https://www.twblogs.net/a/5c946cd5bd9eee35cd6bc370
https://www.espressif.com/sites/default/files/documentation/save_esp8266ex_ram_with_progmem_cn.pdf
RAM 一共2KB,资源很有限,全局变量RAM至少需要预留50%出来,不然串口的数据很容易丢失!!!
4、ESP8266单独供电时,电源打开的顺序问题
如果电源有先后打开的顺序,那么要先打开arduino的电源,然后再打开esp8266的电源;如果搞反了,会导致arduino发送AT指令给wifi模块时没有任何响应!原因是什么呢?飘易猜测:arduion是通过软串口连接wifi的rx、tx引脚的,当arduion通电初始化时,发现软串口连接的2个引脚已经有电平输出,导致软串口初始化失败。
【参考】: