2-CH579M+ESP8266(WiFi)基本控制篇-移植单片机MQTT包,实现CH579M+ESP8266(WiFi)连接MQTT服务器(AT透传和非透传)
<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/ZLCH579M/ESP8266/my.html" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
说明
这节说明一下详细的编写程序实现CH579M+ESP8266(WiFi)连接MQTT服务器程序;
这一节可以移植各个单片机搭配各种串口通信模组上.还是那句话:代码不仅是给别人看的,更是给别人用的;
大家伙一定要始终记住一件事情,MQTT服务器就是个TCP服务器.
和MQTT服务器通信实质上就是TCP通信,只不过数据格式要按照MQTT规定.
大家伙要先准备好已经实现控制模组实现TCP通信的程序
我准备了一份程序
先来看移植过程
1.首先打开程序
配置下连接的路由器信息(根据自己的路由器修改)
我是使用的我封装的ConfigModuleNoBlock框架控制的模组连接TCP服务器
配置的模组是透传模式(模组串口接收的数据直接转发到TCP服务器, 模组从TCP服务器接收的数据直接通过串口输出)
模组返回的数据存储到了环形队列里面,使用的内部空闲中断判断的接收到一条完整的数据
主函数中获取数据的地方
2.把mem和mqtt文件夹放到自己的工程
我提供的工程里面已经有了mem.
3.把mqtt_time_data(&mymqtt);放到1ms定时器里面运行
3.编译工程,找到以下错误
4.这个地方写上把数据发送给TCP服务器的函数
我是使用的串口0和模组通信,而且还是透传模式;所以我就直接使用串口0发送数据就可以
这个地方其实是把缓存里面MQTT打包好的协议数据发给服务器.
关于下面的 mymqtt.timer_out_send = 0; 这个是预防有的模块发送数据之后需要等待,按照提示修改就可以
GSM模块透传模式下每条数据的时间间隔需要保持在20ms以上,所以我直接设置的20
5.配置MQTT参数变量,设置回调函数
#include "mqtt.h" /*MQTT*/ char mqtt_connect_flag=0;//1:Á¬½ÓÉÏMQTT·þÎñÆ÷; 0:δÁ¬½ÓÉÏMQTT·þÎñÆ÷ char mqtt_client_id[50] = "11223344";//ClientID char mqtt_username[20] = "yang";//Óû§Ãû char mqtt_password[50] = "11223344";//ÃÜÂë char mqtt_keepalive = 30;//ÐÄÌø°üʱ¼ä /**¶©ÔÄÖ÷Ìâ³É¹¦**/ void subscribedCb(int pdata){ printf("\r\n³É¹¦¶©ÔÄÖ÷Ìâ\r\n"); } /**¶©ÔÄÖ÷Ìâʧ°Ü**/ void failsubscribedCb(int pdata){ printf("\r\n¶©ÔÄÖ÷Ìâʧ°Ü\r\n"); } /**·¢²¼³É¹¦**/ void PublishedCb(){ printf("\r\n·¢²¼³É¹¦\r\n"); } /*Á¬½ÓÉÏMQTT»Øµ÷º¯Êý*/ void MqttConnect(){ printf("\r\nÁ¬½Ó³É¹¦**********************************************************\r\n"); mqtt_connect_flag = 1; } /**MQTT¶Ï¿ªÁ¬½Ó»Øµ÷**/ void MqttDisConnect(){ printf("\r\nÁ¬½Ó¶Ï¿ª**********************************************************\r\n"); mqtt_init(&mymqtt); mqtt_connect_flag=0; } /** * @brief MQTT½ÓÊÕÊý¾Ý»Øµ÷ * @param topic:Ö÷Ìâ * @param topic_len:Ö÷Ìⳤ¶È * @param data:½ÓÊÕµÄÊý¾Ý * @param lengh:½ÓÊÕµÄÊý¾Ý³¤¶È * @retval None * @warning None * @example **/ void MqttReceive(const char* topic, uint32_t topic_len,const char *data, uint32_t lengh) { } /*MQTT*/ mqtt_init(&mymqtt); mqtt_connect_reg(&mymqtt,MqttConnect);//×¢²áÁ¬½Ó»Øµ÷º¯Êý mqtt_disconnect_reg(&mymqtt,MqttDisConnect);//×¢²á¶Ï¿ªÁ¬½Ó»Øµ÷º¯Êý mqtt_received_reg(&mymqtt,MqttReceive);//×¢²á½ÓÊÕÊý¾Ý»Øµ÷º¯Êý
6.在主循环里写上
//Á¬½ÓÉÏMQTT·þÎñÆ÷ if(mqtt_connect_flag) { mqtt_send_function(&mymqtt);//ÌáÈ¡·¢ËÍ»º´æµÄMQTTÐÒé mqtt_keep_alive(&mymqtt);//´¦Àí·¢ËÍÐÄÌø°ü }
7.在主循环里写上轮训发送MQTT连接协议程序
连接上TCP但是没有连接上MQTT,每隔一段时间发送一次连接协议
关于各个参数函数
8.在处理串口接收的数据里面加上处理MQTT连接消息
提示:判断上是连接消息之后,内部会调用mqtt连接回调函数
9.下载程序到开发板测试
10.保证可靠的断线重连
如果发送了几次连接协议还是没有连接上,让单片机重新控制模组连接TCP
/*³¬¹ýÁ¬½Ó´ÎÊý,ÖØÐÂÅäÖÃÄ£×éÁ¬½ÓTCP*/ mqtt_connect_cnt++; if(mqtt_connect_cnt>3) { mqtt_connect_cnt=0; mqtt_connect_flag=0; /*ÖØÐÂÅäÖÃÄ£¿éÁ¬½ÓTCP*/ ConfigModuleNoBlockCaseValue=0; ConfigModuleNoBlockFlage = 0; }
检测到TCP断开以后控制模块重新连接TCP服务器
11.加上解析处理MQTT接收的数据程序
12.订阅主题
只要是连接上MQTT服务器了,从哪里调用订阅函数都可以.一般是在连接回调里面调用;
假设订阅主题为topic
测试
13.接收消息
如果内存允许的话建议使用拷贝数据的形式,就是把数据先拷贝出来再处理
测试
13.发布消息
只要是连接上MQTT服务器了,可以在任意地方调用发布消息函数
测试
注意事项
接收处理数据是在主轮训里面判断接收到一帧数据标志以后再去处理的,如果主轮训增加了过高的延迟
就会导致缓存里面有粘包数据.这样子的话当前的MQTT处理程序是不去处理的.
首先建议用户不要在主循环随意的加硬延时!!!
再后期我会优化底层,让底层可以处理粘包数据;
当前用户可以使用BufferManage来缓存数据解决上面的问题.