热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

目录写在前面三种方案(利用ESP32连接EMQX下的MQTT)步骤ESP32烧录固件并AT指令进行测试。下载固件烧录工具下载烧录固件

目录

写在前面

三种方案(利用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=  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(); //可设置上电自动连接wifiHAL_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
}


 

 


最后

结束。


推荐阅读
  • C语言编写线程池的简单实现方法
    2019独角兽企业重金招聘Python工程师标准好文章,一起分享——有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带 ... [详细]
  • 使用HTML和JavaScript实现视频截图功能
    本文介绍了如何利用HTML和JavaScript实现从远程MP4、本地摄像头及本地上传的MP4文件中截取视频帧,并展示了具体的实现步骤和示例代码。 ... [详细]
  • 普通树(每个节点可以有任意数量的子节点)级序遍历 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • 在Windows系统中安装TensorFlow GPU版的详细指南与常见问题解决
    在Windows系统中安装TensorFlow GPU版是许多深度学习初学者面临的挑战。本文详细介绍了安装过程中的每一个步骤,并针对常见的问题提供了有效的解决方案。通过本文的指导,读者可以顺利地完成安装并避免常见的陷阱。 ... [详细]
  • C#实现文件的压缩与解压
    2019独角兽企业重金招聘Python工程师标准一、准备工作1、下载ICSharpCode.SharpZipLib.dll文件2、项目中引用这个dll二、文件压缩与解压共用类 ... [详细]
  • Spring Data JdbcTemplate 入门指南
    本文将介绍如何使用 Spring JdbcTemplate 进行数据库操作,包括查询和插入数据。我们将通过一个学生表的示例来演示具体步骤。 ... [详细]
  • 在 Mac 上配置 NDK
    本文详细介绍了如何在 Mac 上配置 Android NDK,包括设置环境变量和解决常见问题的方法。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 题目描述:牛客网新员工Fish每天早上都会拿着一本英文杂志,在本子上写下一些句子。他的同事Cat对这些句子非常感兴趣,但发现这些句子的单词顺序被反转了。例如,“student. a am I”实际上是“I am a student.”。Cat请求你帮助他恢复这些句子的正常顺序。 ... [详细]
  • 三角测量计算三维坐标的代码_双目三维重建——层次化重建思考
    双目三维重建——层次化重建思考FesianXu2020.7.22atANTFINANCIALintern前言本文是笔者阅读[1]第10章内容的笔记,本文从宏观的角度阐 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 本文详细介绍了 Charles 工具的下载、安装、配置及使用方法,特别针对 HTTP 和 HTTPS 协议的数据抓取进行了说明。 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
author-avatar
给糖就不骗你
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有