程单片机解析ESP8266 MQTT数据及MQTT AT固件使用实例

        先简单提一下驱动电路,下图为安信可官方手册

简单来说便是RST低电平触发复位,平时需要跟EN一样分别接10k拉高到3.3V

如果是12E/F的话管脚比较多,GPIO15也要接个1K到地

烧录时GPIO要接地,正常工作时将其拉高或者悬空

主要使用串口通信,烧录固件也是通过串口,烧录时,启动烧录程序后“等待上电同步”状态时,将GPIO0接地,复位一下模块(拉低一下RST),烧录成功开始后GPIO0可以恢复原状。烧录时记得关闭串口助手避免占用串口


        可以通过基础固件透传模式直接连接云平台的,但是我从阿里云换到ThingsCloud之后用同样的方式登录不上了,最后是换成了MQTT固件解决了。

         我使用的是ESP8266的MQTT固件,官网下载,下图为4M大小的版本,如果使用的是ESP01S的话flash容量只有1M,需要使用1M的版本,使用起来没有区别,甚至ESP32与ESP8266也没有什么区别。


完整指令集的链接: 

 MQTT AT 命令集 – ESP32 – — ESP-AT 用户指南 latest 文档 (espressif.com)

常用基础指令:

1. 更改ESP的工作模式:

AT+CWMODE?    //查询设备的WiFi模式

AT+CWMODE=1    //设置设备的WiFi模式为客户端模式/Station模式

        只需要设置一次之后设备便会记住,这一步过后才能连接AP

2.连接AP

AT+CWJAP? //查询连接的 AP 信息 
AT+CWJAP="Upper_of_ESPxx","12345678" //连接AP

        也就是连接WiFi热点,WiFi名称与密码是必要参数,还有更多参数可以翻阅官方手册连接过后,下一次启动模块会自动连接

3.串口设置

AT+UART=9600,8,1,0,0        //设置串口波特率为9600,8数据位,1停止位,0校验位

        一般烧录完固件波特率会变成115200或者76800,如果单片机不支持太高的波特率可以通过电脑发送这条指令给模块更改波特率后再让其与单片机通信

常用MQTT-AT指令:

1.设置 MQTT 用户属性(config):

AT+MQTTUSERCFG=0,1,"client_id","username","password",0,0,""

2.登录云平台(ThingsCloud为例)

物联网平台ThingsCloud简单入门

        在云平台上查看MQTT接入点,除了MQTT还有其他接入的方式,比如TCP接入但是有些需要自定义数据流然后在云里自己用JavaScript写云端的解析函数,只有走MQTT协议的数据云端能够直接自动解析并记录。

AT+MQTTCONN=0,"gz-3-mqtt.iot-api.com",1883,0

通过上面这条指令接入MQTT接入点,MQTT固件会帮咱按照刚才设置的ID和密码登录。

这条指令如果成功执行了,此时就能在云端看到设备上线了

3.订阅消息

只有订阅了相应的主题才能接收到云端下发的相应的信息

比较基础的常用的就是“接收下发的属性”

ThingsCloud的订阅链接藏在文档里

阿里云这边就是“属性设置”

阿里云的订阅链接比较好找但是比较长然后需要自己补齐设备名称

AT+MQTTSUB=0,"attributes/push",0

通过该条指令订阅主题,双引号中间就是ThingsCloud的“接收下发的属性”

4.上报数据

AT+MQTTPUB=0,"attributes","{\"TEMP_N\":28\,\"HUMI_N\":44}",0,0

第一个双引号里是发布链接,第二个双引号内必须符合MQTT协议的格式并且要加上转义字符'\',因为ESP模块会吃掉一层转义,如果通过单片机发送的话还要再吃掉一层。

如果看云端后台没有消息记录,不要第一时间怀疑是发送失败,而是先检查自己的语法,因为云端在这个接入点接收到不符合MQTT协议的数据就会丢掉,后台没有记录。


在调试日志或者MQTT.fx里观察MQTT数据包的格式,一次数据记录都没有的可以云端下发产生第一条。

ThingsCloud
阿里云

 第一张图为ThingsCloud下发的数据,第二张图为阿里云下发的数据,阿里云的要更臃肿一些,但是核心内容部分的格式都是一样的即JSON格式:

{
  "HUMI_H": 57,
  "HUMI_L": 22,
  "TEMP_H": 37,
  "TEMP_L": 22,
  "LCD_A": 0
}
MQTT透传AT固件收到的数据多一层开头

 遇到阿里云这样的多一层的数据包,封装比内容还长的情况,可能比较浪费空间,可以设置接收数据的时候将‘{’作为接收完毕的标志然后将收到的第一二组数据丢弃重新接收,如果使用AT的MQTT固件的话也是会收到一层封装,也可以通过这个方法一并丢弃。

	if(temp==0||temp=='\r'||temp=='\n'||UART_rec.len>=65||temp=='{')//'{'也是句末
	{
	  UART_rec.buff[UART_rec.len]='\0';
	  UART_rec.flag=1;	//数据包接收完成标志
	  UART_rec.len=0; 	//为下一个数据包做准备
	}
	else
	{
	 UART_rec.buff[UART_rec.len++]=temp;
	} 

 解析的思路就是通过"strstr"定位关键词,然后向后偏移固定的位置便可捕捉到我们需要的数据,便可将其设置到我们的全局变量或者外部变量之中:

    p=strstr(str,"D_A");//定位"LCD_A"的位置,p为char*类型
    if(p!=NULL)    //如果有找到
    {
	    *LCD_A=str[(u8)(p-str)+sizeof("D_A\":\"")-1]-48;//偏移固定位置后
                                                        //将字符减去ASCII码变为整形对应数值
    }
	p=strstr((char *)esp32rec.buff,"Admin_psw");//从接收的数据包中定位"Admin_psw"的位置
	if(p==NULL) return 1;        //没有该关键词则p==NULL,做出相应处理
	p+=sizeof("Admin_psw")+3;    //关键词偏移后3个字节开始便是我们需要的数据
	while(*p!='\"')              //逐位设置到全局变量或者外部变量中
	{
		*Admin_psw=*p;
		p++;
	}

上面的代码还可以优化一下,使用atoi()将数字字符串转换为int类型而不是通过ASCII码操作

物联沃分享整理
物联沃-IOTWORD物联网 » 程单片机解析ESP8266 MQTT数据及MQTT AT固件使用实例

发表评论