<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/ZLCH579M/Air724UG/my.html" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
說明
這節說明一下詳細的編寫程序實現CH579M+Air724UG(4G模塊)連接MQTT服務器程序;
這一節可以移植各個單片機搭配各種串口通信模組上.還是那句話:代碼不僅是給別人看的,更是給別人用的;
大家伙一定要始終記住一件事情,MQTT服務器就是個TCP服務器.
和MQTT服務器通信實質上就是TCP通信,只不過數據格式要按照MQTT規定.
大家伙要先准備好已經實現控制模組實現TCP通信的程序
我也准備了兩份(分別是透傳版和非透傳版的TCP連接通信程序)
先來看透傳版的移植過程
1.首先打開透傳版TCP程序,了解一下
我是使用的我封裝的ConfigModuleNoBlock框架控制的模組連接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來緩存數據解決上面的問題.