飘易博客(作者:Flymorn)
订阅《飘易博客》RSS,第一时间查看最新文章!
飘易首页 | 留言本 | 关于我 | 订阅Feed

Arduino利用AT指令连接乐鑫ESP8266实现串口通讯、配网

Author:飘易 Source:飘易
Categories:物联网 PostTime:2019-8-30 9:52:46
正 文:

乐鑫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特性备注
1UTXD
AT 串口发送输出3.3V开机时禁止下拉
2GND


3CH_PD(EN)
模块断电信号3.3V 1)高电平工作; 2)低电平模块供电关掉;
4GPIO2
预留,默认悬空3.3V开机上电时必须为高电平,禁止硬件下拉;内部默认已拉高
5GPIO16I复位信号(RESET)3.3V低电平复位,高电平工作(默认高);
6GPIO0
模块状态灯/工作模式选择3.3V1)默认WiFiStatus:

WiFi工作状态指示灯控制信号;

2)工作模式选择:

上拉:FlashBoot,工作模式;

下拉:UARTDownload,下载模式(下载固件);

7VCCI模块采用单电源供电,通过 1 个VCC 电源引脚供电,电压范围:3.0V-3.6V,电流>600mA

Vmax=3.6V

Vmin=3.0V

Vnorm=3.3V

电源供电能力请大于600mA;否则可能会引起模块工作异常,或者无线性能不好。
8URXD
AT 串口发送输入3.3V

MCU和wifi的通用连接示意图:

如果连接Arduino的话,接线如下(正常工作模式):

WIFI模块Arduino
3V33.3V
EN3.3V
GNDGND
TX6(软串口)
RX7(软串口)

图中的CH_PD引脚就是EN脚。


如果是让wifi和usb转ttl串口设备连接的话,参考下图:



ESP8266固件

正常的乐鑫官方的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


ESP8266 AT指令

我们先看看刷了乐鑫自家的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编写程序

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都不需要了,直接在微信里就可以实现配网啦。

Airkiss配网演示

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,电路图如下:


TIP提示:

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个引脚已经有电平输出,导致软串口初始化失败。



【参考】:

1、安信可ESP8266使用AT指令开发示例


作者:飘易
来源:飘易
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
上一篇:乐鑫ESP8266烧录固件、升级最新固件、刷MQTT固件
下一篇:Arduino控制RGB三色LED灯,实现1600万种酷炫颜色
0条评论 “Arduino利用AT指令连接乐鑫ESP8266实现串口通讯、配网”
No Comment .
发表评论
名称(*必填)
邮件(选填)
网站(选填)

记住我,下次回复时不用重新输入个人信息
© 2007-2019 飘易博客 Www.Piaoyi.Org 原创文章版权由飘易所有