ESP32的MQTT AT固件烧录+STM32以ESP32的MQTT AT固件的AT指令连接EMQX下mqtt服务器实现消息订阅和发布

目录

写在前面

三种方案(利用ESP32连接EMQX下的MQTT)

步骤

ESP32烧录固件并AT指令进行测试。

下载固件

 烧录工具下载

烧录固件(选择ESP32)

 关于AT 指令与MQTT服务器断开后自动重连MQTT服务器

关于AT指令设置上电自动连接WIFI

关于AT指令设置断开后自动重新连接WIFI

STM32对接ESP32(以AT指令交互)

原理:

步骤:

设备: 

连线:

测试:

主要代码: 

效果:

最后


 

写在前面

        ESP32是一块完整的开发板,据我目前所知,它本身自带蓝牙和WIFI,可用arduino和MicroPython单独对其完成开发,以前我用arduino已经试过了。参考我之前的

ESP32(基于Arduino)连接EMQX的Mqtt服务器上传信息与命令控制_昊月光华的博客-CSDN博客_arduino esp32 mqtt

        既然ESP32本身在通信方面上就已经做得足够完美了(最高主频可以达到240MHZ),而且以arduino库开发的方式又极其简单和轻松。奈何让esp32订阅和发布都是相当于另外写一套代码(尽管也很简单,但避免不了新的需求又要增加新的代码),其中包括串口通信的代码(保证不会有信息丢失),还要包括断网自动重连WIFI和与mqtt服务器断开自动重连等辅助代码。试想在这种情况下,需要判断从stm32发过来的信息中是发给那个主题的,不得不继续修改代码增加判断。( (除非单独指定某个串口接受某个主题的数据,然后esp32收到就直接发送对应主题。

三种方案(利用ESP32连接EMQX下的MQTT)

  • 第一种:正如上面的那样,esp32单独工作,stm32与esp32串口通信订阅和发布。(这种比如容易看到效果,因为可以单独进行测试)
  • 第二种:也就是本次我要做的事情,直接用stm32通过AT指令控制ESP32连接wifi,连接mqtt服务器,然后订阅和发布。
  • 第三种:结合前面两种的方案,让esp32单独开发,比如用arduino可以单独订阅和发布,自己规定一套协议,我把它称之为仿AT指令 ,然后约定xxx格式是订阅,xxx格式是发布。好处在于可以自己扩展代码。比如说可以知道另一个连接mqtt服务器的客户端的在线情况。坏处在于:难度较大,需要保证每次的发布信息和收到订阅主题的信息都能无差错。
  • 本次实现第二种:让esp32烧录MQTT 的AT 固件 然后 stm32以发AT 指令的方式完成所有功能。详细见步骤:

    步骤

    ESP32烧录固件并AT指令进行测试。

    这个官方文档上有。

    接线 

     

    下载固件

    esp32的固件链接

    https://docs.ai-thinker.com/_media/esp32/esp32-s_at2.2-sdk4.0.1-uart0.rar

     

     烧录工具下载

    Flash烧录工具的下载链接:工具 | 乐鑫科技

    下载解压后图示 

     

     

    烧录固件(选择ESP32)

    打开烧录工具

     选择后(如下配置只有被勾选的那一行是有效的)

    在烧录之前,把esp32设置成自动下载模式,先按EN,同时按下IO0

    串口打印出

    rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
    waiting for download

     说明进入了下载模式

     start后,开始下载

     

    完成后复位测试AT指令。(需要注意的是AT指令格式必须是严格的,比如以下带AT的指令,AT前不能有空格,后面也不能有空格,另外串口调试助手发送还必须带回车符。

    在进行以下AT指令测试之前,本地EMQX的mqtt服务器要安装后并在bin路径下 

    emqx start

    启动。

     

     进行AT指令测试。(附上官网文档上的指令)

    更多关于WIFI 的AT指令和MQTT 的AT指令集参考乐鑫官网

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

    发送AT指令的顺序:

    AT                                                                                     #测试AT功能

    AT+CWMODE=1                                                          #设置模组进入STA模式

    AT+CWJAP="ssid","password"                               #连接wifi

    AT+MQTTUSERCFG=0,1,"用户ID","账号","密码",0,0,""

    # 设置MQTT连接所需要的的参数,包括用户ID(不为空)、

    # 账号(admin)以及密码(public)

    AT+MQTTCONN=0,"本地IP",1883,0

    AT+MQTTPUB=0,"对应主题","发布主题对应信息",0,0          //发布对应主题信息                                            

    AT+MQTTSUB=0,"订阅的主题名",0      //订阅对应的主题

     

     串口助手下AT 指令测试

    若连接mqtt服务器返回 ERROR 

    先调用 MQTT+CLEAN=0 清除MQTT的连接信息。再重新连接。

     

     

     关于AT 指令与MQTT服务器断开后自动重连MQTT服务器

    AT+MQTTCONN=0,"192.168.1.13",1883,0(以连接本地为例,0改成1即可,经过测试,手动断开服务器连接后能自动重连)

    关于AT指令设置上电自动连接WIFI

    AT+CWAUTOCONN=<enable>  0:上电不自动连接 1:上电自动连接

    关于AT指令设置断开后自动重新连接WIFI

    AT+CWRECONNCFG=1,0  //断开后每隔1s自动重连,始终尝试自动重连

    到这,把esp32断网自动重连WIFI和mqtt服务器都设置完毕。

     

    STM32对接ESP32(以AT指令交互)

    原理:

    让stm32以串口的形式发送给ESP32代替串口调试助手与ESP32进行交互。需要注意的是在连接时适当的延时保证ESP32处理完数据。(若不延时,我测试时有可能会连接失败)

    步骤:

    1. STM32发AT指令控制ESP32正常连接EMQX下的mqtt服务器并订阅相关主题
    2. 用paho MQTT客户端也连接mqtt服务器,并发布相应主题
    3. stm32收到信息进行数据处理,判断是哪个主题发来的并解析出具体消息。

     

    设备: 

    其中STM32是F103C8T6最小系统开发板。

    连线:

    stm32的串口2连接ESP32的串口1。stm32的串口2以DMA加空闲中断接受数据。

    测试:

    esp32收到stm32发过来的AT指令订阅"hello"主题,用paho客户端或EMQX下的websocket发布主题信息,以json格式发送,esp32收到后发送到stm32,stm32解析出对应数据信息。

    主要代码: 

    我的代码中难免有败笔,只考虑了正常情况,敬请指出。 

    mqtt.c

    
    
    
    #include "mqtt.h"
    
    
    
    
    
    
    u16 MAXCONNECT_TIME=0;
    
    u8 Rx2_Buf[180]={0};   //接受ESP32模块信息
    u8 Rx2_sBuf[180]={0};  //发送缓存数组 以DMA方式
    u8 Rx2_Cnt=0;
    
    __IO u8  mqttstate=0;
    char wifi_uid[]="rookie";
    char wifi_pwd[]="yy061457";
     
    
    
    //连接WIFI  ESP32可以设置为自动重连
    void ConnectWifi(void){
        
        sprintf((char *)Rx2_sBuf,CONNECTWIFI,wifi_uid,wifi_pwd);
      
        HAL_UART_Transmit(&huart2,Rx2_sBuf,strlen((const char *)Rx2_sBuf),10);
      
        
    }
    
    
     //清除MQTT连接
    void CleanMqttInfo(void){
         
        HAL_UART_Transmit(&huart2,(uint8_t *)CLEANMQTTINFO,sizeof(CLEANMQTTINFO),10);
        printf("%s\r\n",CLEANMQTTINFO);
     
        
    }
    
     //登录认证
    void ConnectMQTTServer(void){
        
        //清除先前遗留连接信息
          CleanMqttInfo();  
        
        HAL_Delay(500);
        //登录认证
        HAL_UART_Transmit(&huart2,(u8*)LOGINMQTT,sizeof(LOGINMQTT),20);
        printf("%s\r\n",LOGINMQTT);
         HAL_Delay(500);
        
        
        //连接mqtt服务器
        HAL_UART_Transmit(&huart2,(u8*)CONNECTMQTT,sizeof(CONNECTMQTT),20);
        printf("%s\r\n",CONNECTMQTT);
        HAL_Delay(1000);
         
    }
    
    
    //连接WIFI与MQTT服务器
    void MQTT_Init(void){
        
    
        
                        ConnectWifi();     //可设置上电自动连接wifi
                        HAL_Delay(5000);
                         mqttstate=1;
                         ConnectMQTTServer();
                        while(mqttstate!=2){
      
                            ConnectMQTTServer();
                             HAL_Delay(1000);
                        }
                       printf("Connect mqtt success\r\n");
                     
                        SubAssignTopic("hello"); //订阅相关主题
                        
                        HAL_Delay(1000);
            
    }
    
    ///订阅指定主题
    void SubAssignTopic(char * subtopic){
        
        sprintf(Rx2_sBuf,SUBTOPIC,subtopic);
        printf("%s\r\n",Rx2_sBuf);
        HAL_UART_Transmit(&huart2,Rx2_sBuf,sizeof(Rx2_sBuf),10);
    
    }
    
    
    
    
    //获取对应主题和对应信息(JSON格式),以及json数据报长度
    void GetTopicAndMsg(char * p,char * src,char* topic, char* cnt,int len,char * msg) {
    
        while (*p != '"' && p != &src[len - 1])p++; //匹配第一个引号
    
    
        if (*p++ == '"') {
            char start = 0;
            while (*p != '"' && p != &src[len - 1]) {
                topic[start++] = *p++;
            }
    
            if (*p++ == '"') {  //匹配第二个引号
                topic[start] = '\0';
                printf("[topic]:%s\r\n", topic);  //主题获取完毕
                
            }
            if (*p == ',' && p!= &src[len-1]) { //匹配第一个逗号
                p++;
                char temp[3] = { 0 };
                char j = 0;
                while (*p!=',' && p != &src[len-1])
                {
                    temp[j++] = *p++;
                }
                *cnt = atoi(temp);//得到长度
                printf("[CNT]:%d\r\n", *cnt);
                if (*p++ == ',') {//匹配描述消息体长度的最后一个逗号
                    j = 0;
                    while (p != &src[len]) {  
                        msg[j++] = *p++;
                    }
                    msg[j] = '\0';
                    printf("[msg]:%s\r\n", msg);
    
                }   
            }
           
        }
    
    }
    
    
    void Test(void){
        
        char topic[30]={0};
        char msg[160]={0};
           char* p = strstr((const char *)Rx2_Buf, "MQTTSUBRECV");
            if(p){
              u8 len =strlen((const char *)Rx2_Buf);
              char cnt=0;
                 //获取主题与json数据报
                GetTopicAndMsg(p ,Rx2_Buf,  topic,&cnt,  len,  msg);
                
                
                 json_error_t error;
                 json_t *root;
                 root = json_loads((const char*)msg, 0, &error); 
                if(json_is_object(root))  //是json格式数据
                {
                            //解析json数据
                    if(strcmp(topic,"hello") == 0){
                        char *name=(char *)json_string_value(json_object_get(root, "name"));
                     int val1=json_integer_value(json_object_get(root, "val1"));
                     int val2=json_integer_value(json_object_get(root, "val2"));
                     int val3=json_integer_value(json_object_get(root, "val3"));
                     //测试解析后的数据
                     printf("parse name:%s-val1:%d-val2:%d-val3:%d\r\n",name,val1,val2,val3);
                                 
                        }
                         
                     //释放内存
                      json_decref(root);
                        
                    }
                else  //非json格式数据
                {
                     printf("format error:%d-%s\r\n", error.line, error.text);
                    
                }
                    
                
                
                
                
     
            }
                
            
           
        
    }
    
    
    //发布信息到指定主题
    void PubMsgByTopic(char * topic,char * msg){
        
        sprintf(Rx2_sBuf,topic,msg);
        HAL_UART_Transmit(&huart2,Rx2_sBuf,sizeof(Rx2_sBuf),10);
        
    }
    
    
    
    
    
    
    
    
    
    

    mqtt.h

    
    
    #ifndef __MQTT_H_
    #define __MQTT_H_
    
    
    
    
    #include "template.h"
    
    void ConnectWifi(void);
    void ConnectMQTTServer(void);
        
      
      
    extern u8 Rx2_Buf[180];
    extern u8 Rx2_sBuf[180];
    
    
    extern __IO u8 mqttstate;
    
    
    //订阅主题格式
    #define SUBTOPIC   "AT+MQTTSUB=0,\"%s\",0\r\n"
    
     //发布对应主题对应信息格式
    #define PUBTOPIC  "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n"
    
    //连接对应WIFI  账号 密码
    #define CONNECTWIFI  "AT+CWJAP=\
    \"%s\",\
    \"%s\"\r\n"
    
    //清除MQTT连接信息
     #define  CLEANMQTTINFO "AT+MQTTCLEAN=0\r\n"
     
     
     
     //连接EMQX服务器的本地登录账号和密码
     #define LOGINMQTT "AT+MQTTUSERCFG=0,1,\
    \"ESP\",\
    \"admin\",\
    \"061457\",\
    0,0,""\
    \r\n"
    
    //连接本地EMQX 下的mqtt服务器地址 设置断开自动重连
    #define  CONNECTMQTT "AT+MQTTCONN=0,\"192.168.1.13\",1883,1\r\n"
     
    
        
        
        
        
        
    extern u16  MAXCONNECT_TIME;
    void SubAssignTopic(char * subtopic);
    void PubMsgByTopic(char * topic,char * msg);
    void MQTT_Init(void);
    
    
    void  Test(void);
    #endif
    
    
    

     

    效果:

    发布hello主题 

    json 数据如下

    {
    "name":"yzh",
    "val1":1,
    "val2":2,
    "val3":3
    }

     

     

    最后

    结束。

    物联沃分享整理
    物联沃-IOTWORD物联网 » ESP32的MQTT AT固件烧录+STM32以ESP32的MQTT AT固件的AT指令连接EMQX下mqtt服务器实现消息订阅和发布

    发表评论