前言
注:
本程序發送心跳包,發送溫濕度,返回控制數據這三個發送是單獨的,有可能湊到一起發.
由於本身程序就是復雜性的程序,所以這節程序沒有使用中斷發送,沒有使用環形隊列發送,為了避免多條消息可能湊到一起發

如果嫌棄這個延時請自行優化,或者采用自己的方式解決,謝謝支持!
抱歉哈!我首先期望的是大部分人都先要看懂程序,至於其他優化我會提供個思路和源碼,大家可以根據自己的情況自行優化.

用戶須知
整個程序是STM32使用AT指令控制Wi-Fi模塊實現SmartConfig配網和MQTT通信控制
程序的整體結構: https://www.cnblogs.com/yangfengwu/p/11669323.html
程序的按鍵處理: https://www.cnblogs.com/yangfengwu/p/11669354.html
串口接收數據 : https://www.cnblogs.com/yangfengwu/p/11669373.html
配置AT指令模板(阻塞版): https://www.cnblogs.com/yangfengwu/p/11673439.html
配置AT指令模板(非阻塞版): https://www.cnblogs.com/yangfengwu/p/11674814.html
打開這節源碼

修改連接自己的服務器
一,如果想連接自己的MQTT服務器,可以直接更改

SmartConfig配網
一,主循環

二,AT指令配置模塊啟動SmartConfig的程序處理模板是:配置AT指令模板(阻塞版)
三,按鍵按下3S以后 變量 SmartConfigFlage = 1;

定時器里面開始控制 指示燈100Ms閃耀

四,AT指令控制Wi-Fi模塊執行SmartConfig 配網程序部分

五,SmartConfig執行流程-連接路由器

實際上啟用SmartConfig指令是 AT+CWSTARTSMART=3\r\n
最后的參數 1-SmartConfig配網 2-微信Airkiss配網 3-SmartConfig配網+微信Airkiss配網
下面進入了 while(1) 循環 我設置的30S超時
實際上此時Wi-Fi模塊正在監聽APP在空氣中發出的無線信號
下圖只要執行了搜索設備,APP就在不停的發出無線信號

Wi-Fi模塊接收到APP發出的路由器信息以后,就會根據信息去連接路由器
Wi-Fi模塊連接上了路由器以后便會返回 WIFI CONNECTED 和 WIFI GOT IP
注:只要配網一次,以后Wi-Fi模塊便會自動連接此路由器,不需要重復配網!
六,SmartConfig執行流程-等待路由器把自己的MAC信息返回給APP

為了讓APP確定Wi-Fi模塊確實連接上了路由器,Wi-Fi連接上路由器以后
需要返回給APP自己的MAC地址和自己連接路由器后分得的IP地址
所以延時了5S時間,讓Wi-Fi模塊把信息發給APP
下圖中,顯示的就是所配網的Wi-Fi模塊的MAC地址信息
當然MAC地址很有用(全球唯一),通信的時候可以用來區分設備.

控制Wi-Fi模塊連接TCP服務器
配置Wi-Fi模塊連接TCP服務器是使用的 "AT+SAVETRANSLINK=1,\"%s\",%s,\"TCP\"\r\n",IP,Port
這個指令配置好以后,Wi-Fi模塊便是透傳模式,而且是自動連接
(串口接收的數據,自動發給TCP服務器)
(從TCP服務器接收的數據自動發給串口)

MQTT服務器規定ClientID必須每個設備不能一樣,Wi-Fi模塊的MAC作為了ClientID
獲取ClientID部分


ClientID 最終存儲在了 MQTTid數組里面
發送連接MQTT協議


判斷連接狀態



官方庫里面判斷返回的數據都是使用
MQTTPacket_read(數據解析完存到的數組,數組長度,提取數據函數)
最主要的是這個 提取數據函數
transport_getdata

這個函數的格式不能變,官方規定的就是這個格式
因為我的模塊是串口透傳模式,所以MQTT服務器返回的數據都返回到了串口數組里面
Usart1ReadBuff
假設我現在判斷接收的數據類型,(MQTT協議里面第一個返回的數據就能判斷出來數據類型)
MqttAnalyzeStruct.Len=0;
transport_getdata(buff,1);
這樣執行以后 我就把第一個數據 拷貝到了 buff里面

然后我只需要判斷buff數組第一個數據就可以了
其實官方就是這樣做的

提取其它數據

接着看訂閱



此函數一次性可以訂閱多個主題,列如訂閱兩個主題
char SubTopic1[10]="aaaaa";
char SubTopic2[10]="bbbbb";
MQTTString MQTTStringSubTopic[2] = MQTTString_initializer;
int MQTTStringSubTopicQos[2] = {0,1};//第一個主題的消息等級0,第二個消息等級1
MQTTStringSubTopic[0].cstring = SubTopic1;
MQTTStringSubTopic[1].cstring = SubTopic2;
MainLen = MqttSubscribe(MQTTStringSubTopic,MQTTStringSubTopicQos,2,0,1);
UsartOutStr(MqttSendData,MainLen);
注:我設置的一次性最多訂閱3個主題


定義的主題個數大於了此變量,用戶需要增大此變量
實際訂閱的主題個數 <= MaxSubTopicCount
判斷訂閱是否成功


發送一條上線消息
一,定義發布的主題變量
MQTTPublishTopicStruct MqttPublishTopicStruct = MQTTPublishTopicStruct_initializer;
該變量在主函數中定義

二, 使用該變量


打包數據函數 MqttPublish

三,,定義多個發布的主題變量
char Publish1[10]="qqqqq";//發布的主題
char Publish1Msg[8]="11223344";//發布的主題,攜帶的消息
char Publish2[10]="wwww";//發布的主題
char Publish2Msg[6]="000000";//發布的主題,攜帶的消息
MQTTPublishTopicStruct MqttPublishTopicStruct1 = MQTTPublishTopicStruct_initializer;
MQTTPublishTopicStruct MqttPublishTopicStruct2 = MQTTPublishTopicStruct_initializer;
MqttPublishTopicStruct1.topicName.cstring = Publish1;// 發布的主題
MainLen = MqttPublish(MqttPublishTopicStruct1,Publish1Msg,8);
UsartOutStr(MqttSendData,MainLen);//發送消息
MqttPublishTopicStruct1.topicName.cstring = Publish2;// 發布的主題
MainLen = MqttPublish(MqttPublishTopicStruct2,Publish2Msg,6);
UsartOutStr(MqttSendData,MainLen);//發送消息
連接好MQTT,訂閱完主題,然后就是處理MQTT數據


三,每隔一段時間采集發送溫濕度數據

看下我的心跳包處理


說下我的處理思路
首先,如果到了發送心跳包的時間了,就發送一次心跳包
然后啟動超時,超過3S如果服務器沒有回復心跳應答
我就再發送一次,然后啟動超時,如果超過3S還是沒有收到心跳返回
重新配置模塊
