你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32+ESP8266通过AT指令WIFI连接阿里云MQTT服务器

[复制链接]
STMCU小助手 发布时间:2022-3-16 11:31
    上一篇使用USB转串口的方式通过ESP8266wifi模块的方式成功连接上了阿里云,现在就要通过单片机来替换电脑上位机了,这样单片机自动的去调用并发送串口数据更加方便,也更加符合一个产品的开发。板载的传感器有NTC温度,光强,这两个主要用来设备上传到平台,另外一个是RGB的灯,这个主要是用来平台下发设备的接收和解析。这里为了直观我直接用串口打印出来。只要数据部分对了其他的都好说。
`RAB`OEW$ABE`2QAOX431DT.png

网页上的运行状态图

DMQQN_}6SP)ZI550}S8J7MN.png

温度曲线图

7QY221`1MJ8SF)VY)1{SQ[E.png

光强曲线图

UAPMBBGIE%@7RX$B1APCSOR.png

颜色色值曲线图,这里其实是通过单片机随机函数生成的一个数据,所以变化也是比较大的,为了直观我也把这个值上传到平台。

@`W1AZU{@]5LM)3@9LN$FYA.png

平台下发数据、设备解析测试。

这里要注意一下,最开始我通过strstr方法来找出关键字“hue”,但是测了下不行,后来找到原因,估计是平台下发的josn数据包中含有多个0,比方说设备收到的是“123456\0789”,这里的‘\0’其实hex就是0x00,也正好是字符串的结尾标识符,这样通过strstr要找出“789”就找不到的,因为再者之前字符串就认为已经是断了,后来自己写了一个查找函数,解决!

网络部分和MQTT部分我都做了封装,非常方便参考和移植,不多说直接贴上代码:

main.c部分

  1. #include "fy_includes.h"
  2. #include "fy_tlink.h"
  3. /*
  4. 晶振使用的是16M 其他频率在system_stm32f10x.c中修改
  5. 使用printf需要在fy_includes.h修改串口重定向为#define PRINTF_USART USART1
  6. */

  7. _typdef_adc _adc;
  8. u16 adc_light;
  9. u16 adc_ntc;
  10. u16 battery;
  11. float temperature;
  12. u8 led_sta;
  13. u8 sta;
  14. void Adc_GetValue(void);

  15. u8 txbuf[256];
  16. u8 rxbuf[256];

  17. char mqtt_message[200];


  18. void Mqtt_Progress(u8 *buf,u16 len);

  19. void UsartTrance(void)
  20. {
  21.         while(1)
  22.         {
  23.                 Led_Tog();
  24.                 Delay_ms(500);
  25.         }
  26. }

  27. int main(void)
  28. {
  29.         u8 cnt_2s=0;
  30.         u16 cnt_5s=0;
  31.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  32.     Systick_Configuration();
  33.     Led_Configuration();
  34. //        UsartTrance();
  35.         Key_Configuration();
  36.         Adc_Configuration();
  37.         Adc_DMA_Configuration((u32)&_adc.buf,ADC_FILTER*ADC_CH_MAX);
  38.         Usart1_Configuration(115200);
  39.         Usart2_Configuration(115200);
  40.         Oled_Configuration();
  41.         Usart1_SendString("  usart1 is ok!\r\n");
  42. //        Usart2_SendString("  usart2 is ok!\r\n");
  43.         Delay_ms(200);
  44.         
  45. //        UsartTrance();
  46.         sta=0;
  47.         
  48.         //检查ESP8266
  49.     if(_net.Init(rxbuf,sizeof(rxbuf),txbuf,sizeof(txbuf))!=0){
  50.                 Oled_ShowString(0,0*16,"Net Init OK!",8,16,1);
  51. //                printf("Net Init OK!\r\n");
  52.                 sta++;
  53.         }
  54.         else{
  55.                 Oled_ShowString(0,0*16,"Net Init Error!",8,16,1);
  56. //                printf("Net Init Error!\r\n");
  57.                 sta=0;
  58.         }
  59.         Oled_RefreshGram();
  60.         
  61.         if(sta==1){
  62.                 //连接热点
  63.                 if(_net.ConnectAP("ssid","password")!=0){
  64.                         Oled_ShowString(0,1*16,"Conncet AP OK!",8,16,1);
  65. //                        printf("Conncet AP OK!\r\n");
  66.                         sta++;
  67.                 }
  68.                 else {
  69.                         Oled_ShowString(0,1*16,"Conncet AP Error!",8,16,1);
  70. //                        printf("Conncet AP Error!\r\n");
  71.                         sta=0;
  72.                 }
  73.                 Oled_RefreshGram();
  74.         }
  75.         
  76.         if(sta==2){        
  77.                 //连接TCP
  78.                 if(_net.ConnectServer("TCP","a1ugBNniFGU.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883)!=0) {
  79.                         Oled_ShowString(0,2*16,"Conet Server OK!",8,16,1);
  80. //                        printf("Conncet Server OK!\r\n");
  81.                         sta++;
  82.                 }
  83.                 else{
  84.                         Oled_ShowString(0,2*16,"Server Error!",8,16,1);
  85. //                        printf("Conncet Server Error!\r\n");        
  86.                         sta=0;
  87.                 }
  88.                 Oled_RefreshGram();
  89.         }
  90.         
  91.         if(sta==3){
  92.                 //登录MQTT
  93.                 _mqtt.Init(rxbuf,sizeof(rxbuf),txbuf,sizeof(txbuf));               
  94.                 if(_mqtt.Connect(
  95.                         "123456|securemode=3,signmethod=hmacsha1,timestamp=789|",//ClientID
  96.                         "FY-STM32&a1ugBNniFGU",//Username
  97.                         "b447b9f26938d8eba6b2a4878066aae91839600c"//Password
  98.                         ) != 0){
  99.                         Oled_ShowString(0,3*16,"Enter MQTT OK!",8,16,1);
  100. //                        printf("Enter MQTT OK!\r\n");
  101.                         sta++;
  102.                 }
  103.                 else{               
  104.                         Oled_ShowString(0,3*16,"Enter MQTT Error",8,16,1);
  105. //                        printf("Enter MQTT Error!\r\n");
  106.                         sta=0;
  107.                 }        
  108.                 Oled_RefreshGram();
  109.         }        
  110.         
  111.         if(sta==4){
  112.                 Oled_Clear();
  113.                 //订阅主题
  114.                 if(_mqtt.SubscribeTopic("/sys/a1ugBNniFGU/FY-STM32/thing/service/property/set",0,1) != 0){
  115.                         Oled_ShowString(0,0*16,"Subscribe OK!",8,16,1);
  116. //                        printf("SubscribeTopic OK!\r\n");
  117.                 }
  118.                 else{                        
  119.                         Oled_ShowString(0,0*16,"Subscribe Error!",8,16,1);
  120. //                        printf("SubscribeTopic Error!\r\n");
  121.                 }
  122.                 Oled_RefreshGram();               
  123.         }
  124.         Delay_ms(1000);
  125.         Oled_Clear();                        
  126.         Oled_ShowString(32,0*16,"Mars Tech",8,16,1);
  127.         Oled_ShowString(0,1*16," VCC: 0000 mV",8,16,1);
  128.         Oled_ShowString(0,2*16,"Temp: 00.0 C",8,16,1);
  129.         Oled_ShowString(0,3*16," LUX: 0000  ",8,16,1);
  130.         Oled_RefreshGram();
  131.         sta = 0;
  132.     while(1)
  133.     {
  134.                 if(++cnt_2s>=200){
  135.                         cnt_2s=0;
  136.                         Adc_GetValue();
  137.                         temperature = Ntc_GetTemp(adc_ntc)*0.1f;
  138.                         Oled_ShowNum(8*6,1*16,battery,4,8,16);                        
  139.                         Oled_ShowNum(8*6,2*16,(u8)temperature,2,8,16);
  140.                         Oled_ShowNum(8*6+3*8,2*16,(u16)(temperature*10)%10,1,8,16);                        
  141.                         Oled_ShowNum(8*6,3*16,adc_light,4,8,16);
  142.                         
  143.                         Oled_RefreshGram();
  144.                 }
  145.                 if(++cnt_5s>=500){//
  146.                         cnt_5s=0;
  147.                         sprintf(mqtt_message,
  148.                         "{"method":"thing.service.property.set","id":"630262306","params":{\
  149.                                 "CurrentTemperature":%.1f,\
  150.                                 "hue":%d,\
  151.                                 "mlux":%d\
  152.                         },"version":"1.0.0"}",
  153.                         temperature,
  154.                         rand()%0x00ffffff,
  155.                         adc_light
  156.                         );
  157.                         
  158.                         _mqtt.PublishData("/sys/a1ugBNniFGU/FY-STM32/thing/event/property/post",mqtt_message,0);                        
  159.                 }
  160.                 if(_mqtt.rxlen){
  161.                         Mqtt_Progress(_mqtt.rxbuf,_mqtt.rxlen);               
  162.                         memset(_mqtt.rxbuf,0,_mqtt.rxlen);
  163.                         _mqtt.rxlen = 0;
  164.                 }                        
  165.                 Delay_ms(10);
  166.     }
  167. }

  168. void Adc_GetValue(void)
  169. {
  170.         u32 sum[ADC_CH_MAX];        
  171.         memset(sum,0,sizeof(sum));
  172.         for(u8 ch=0; ch<ADC_CH_MAX; ch++)
  173.         {
  174.                 for(u8 filter=0; filter<ADC_FILTER; filter++)
  175.                 {
  176.                         sum[ch] += _adc.buf[filter][ch];//计算累加和
  177.                 }               
  178.         }
  179.         adc_light = sum[ADC_LIGHT]/ADC_FILTER;
  180.         adc_ntc = sum[ADC_NTC]/ADC_FILTER;
  181.         battery = sum[ADC_VCC]/ADC_FILTER*3300/4095*11;         //mV
  182. }

  183. u8 temp;
  184. void USART2_IRQHandler(void)
  185. {
  186.     static u8 rxlen = 0;

  187.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //判断接收数据寄存器是否有数据
  188.     {
  189.                 temp = USART2->DR;
  190. //                USART1->DR = temp;//这里用作串口1打印WIFI模块发送的数据
  191.                 if(rxlen>=255) rxlen=0;
  192.         rxbuf[rxlen++] = temp;
  193.         rxlen%=sizeof(rxbuf);
  194.     }

  195.     if(USART_GetITStatus(USART2, USART_IT_IDLE))
  196.     {
  197.                 temp = USART2->DR;
  198.                 temp = USART2->SR;
  199.                 _mqtt.rxlen = rxlen;
  200. //                Mqtt_Progress(rxbuf,rxlen);//主循环做异步处理
  201.                 rxlen=0;
  202.     }
  203. }
  204. //void *StrStr(void *dest,void *src);

  205. u8 *p;
  206. void Mqtt_Progress(u8 *buf,u16 len)
  207. {
  208.         char *keyStr = "hue";
  209.         u8 keyStrLen = strlen(keyStr)-1;
  210.         u8 i,j;
  211.         for(i=0;i<len-keyStrLen;i++)
  212.         {
  213.                 for(j=0;j<keyStrLen;j++)
  214.                 {
  215.                         if(buf[i+j] != keyStr[j])        break;
  216.                 }        
  217.                 if(j==keyStrLen) break;
  218.         }
  219.         if(i<=len-keyStrLen)
  220.     {
  221.                 u16 temp = 0;
  222.                 p = &buf<i>;
  223.                                 
  224.                 while(*p != ':') p++;
  225.                 p++;
  226.                 while(*p != '}')
  227.                 {
  228.                         temp = temp *10 + (*p - '0');
  229.                         p++</i>;
  230.                 }
  231.                 printf("receive message, hue = %d \r\n",temp);
  232. //                Usart1_SendBuf(buf,len);
  233.     }
  234. }

  235. /*********************************************END OF FILE********************************************/
复制代码


net.c部分

  1. #include "fy_network.h"

  2. //#define _DEBUG_NET

  3. static u8 Check(void);
  4. static u8 Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);
  5. static void Restore(void);
  6. static u8 ConnectAP(char* ssid,char* pswd);
  7. static u8 ConnectServer(char* mode,char* ip,u16 port);
  8. static u8 DisconnectServer(void);
  9. static u8 OpenTransmission(void);
  10. static void CloseTransmission(void);
  11. static void SendString(char* str);
  12. static void SendBuf(u8* buf,u16 len);


  13. _typdef_net _net=
  14. {
  15.         0,0,
  16.         0,0,
  17.         Check,
  18.         Init,
  19.         Restore,
  20.         ConnectAP,
  21.         ConnectServer,
  22.         DisconnectServer,
  23.         OpenTransmission,
  24.         CloseTransmission,
  25.         SendString,
  26.         SendBuf
  27. };

  28. /**
  29. * 功能:初始化ESP8266
  30. * 参数:None
  31. * 返回值:初始化结果,非0为初始化成功,0为失败
  32. */
  33. static u8 Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen)
  34. {
  35.         _net.rxbuf = prx;_net.rxlen = rxlen;
  36.         _net.txbuf = ptx;_net.txlen = txlen;
  37.         
  38.         memset(_net.rxbuf,0,_net.rxlen);
  39.         memset(_net.txbuf,0,_net.txlen);
  40.         
  41.         _net.CloseTransmission();          //退出透传
  42.     Delay_ms(500);
  43.         _net.SendString("AT+RST\r\n");   //重启ESP8266
  44.         Delay_ms(800);
  45.     if(_net.Check()==0)              //使用AT指令检查ESP8266是否存在
  46.     {
  47.         return 0;
  48.     }

  49.     memset(_net.rxbuf,0,_net.rxlen);    //清空接收缓冲
  50.     _net.SendString("ATE0\r\n");             //关闭回显
  51.     if(FindStr((char*)_net.rxbuf,"OK",500)==0)  //设置不成功
  52.     {
  53.         return 0;      
  54.     }
  55.     return 1;                         //设置成功

  56. }

  57. /**
  58. * 功能:恢复出厂设置
  59. * 参数:None
  60. * 返回值:None
  61. * 说明:此时ESP8266中的用户设置将全部丢失回复成出厂状态
  62. */
  63. static void Restore(void)
  64. {
  65.         _net.CloseTransmission();           //退出透传
  66.     Delay_ms(500);
  67.         _net.SendString("AT+RESTORE\r\n");//恢复出厂         
  68. //    NVIC_SystemReset();                 //同时重启单片机   
  69. }

  70. /**
  71. * 功能:检查ESP8266是否正常
  72. * 参数:None
  73. * 返回值:ESP8266返回状态
  74. *        非0 ESP8266正常
  75. *        0 ESP8266有问题  
  76. */
  77. static u8 Check(void)
  78. {
  79.         u8 check_cnt=5;
  80.         while(check_cnt--)
  81.         {
  82.                 memset(_net.rxbuf,0,_net.rxlen);          //清空接收缓冲
  83.                 _net.SendString("AT\r\n");                      //发送AT握手指令        
  84.                 if(FindStr((char*)_net.rxbuf,"OK",200) != 0)
  85.                 {
  86.                         return 1;
  87.                 }
  88.         }
  89.         return 0;
  90. }

  91. /**
  92. * 功能:连接热点
  93. * 参数:
  94. *         ssid:热点名
  95. *         pwd:热点密码
  96. * 返回值:
  97. *         连接结果,非0连接成功,0连接失败
  98. * 说明:
  99. *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
  100. *         1. WIFI名和密码不正确
  101. *         2. 路由器连接设备太多,未能给ESP8266分配IP
  102. */
  103. static u8 ConnectAP(char* ssid,char* pswd)
  104. {
  105.         u8 cnt=5;
  106.         while(cnt--)
  107.         {
  108.                 memset(_net.rxbuf,0,_net.rxlen);     
  109.                 _net.SendString("AT+CWMODE_CUR=1\r\n");              //设置为STATION模式        
  110.                 if(FindStr((char*)_net.rxbuf,"OK",200) != 0)
  111.                 {
  112.                         break;
  113.                 }                             
  114.         }
  115.         if(cnt == 0)
  116.                 return 0;

  117.         cnt=2;
  118.         while(cnt--)
  119.         {
  120.                 memset(_net.txbuf,0,_net.txlen);                            //清空发送缓冲
  121.                 memset(_net.rxbuf,0,_net.rxlen);                            //清空接收缓冲
  122.                 sprintf((char*)_net.txbuf,"AT+CWJAP_CUR="%s","%s"\r\n",ssid,pswd);//连接目标AP
  123.                 _net.SendString((char*)_net.txbuf);        
  124.                 if(FindStr((char*)_net.rxbuf,"OK",8000)!=0)                      //连接成功且分配到IP
  125.                 {
  126.                         return 1;
  127.                 }
  128.         }
  129.         return 0;
  130. }

  131. /**
  132. * 功能:使用指定协议(TCP/UDP)连接到服务器
  133. * 参数:
  134. *         mode:协议类型 "TCP","UDP"
  135. *         ip:目标服务器IP
  136. *         port:目标是服务器端口号
  137. * 返回值:
  138. *         连接结果,非0连接成功,0连接失败
  139. * 说明:
  140. *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
  141. *         1. 远程服务器IP和端口号有误
  142. *         2. 未连接AP
  143. *         3. 服务器端禁止添加(一般不会发生)
  144. */
  145. static u8 ConnectServer(char* mode,char* ip,u16 port)
  146. {
  147.         u8 cnt;

  148.     _net.CloseTransmission();                   //多次连接需退出透传
  149.     Delay_ms(500);

  150.         //连接服务器
  151.         cnt=2;
  152.         while(cnt--)
  153.         {
  154.                 memset(_net.rxbuf,0,_net.rxlen);      
  155.                 memset(_net.txbuf,0,_net.txlen);   
  156.                 sprintf((char*)_net.txbuf,"AT+CIPSTART="%s","%s",%d\r\n",mode,ip,port);
  157.                 _net.SendString((char*)_net.txbuf);
  158.                 if(FindStr((char*)_net.rxbuf,"CONNECT",8000) !=0 )
  159.                 {
  160.                         break;
  161.                 }
  162.         }
  163.         if(cnt == 0)
  164.                 return 0;
  165.         
  166.         //设置透传模式
  167.         if(_net.OpenTransmission()==0) return 0;
  168.         
  169.         //开启发送状态
  170.         cnt=2;
  171.         while(cnt--)
  172.         {
  173.                 memset(_net.rxbuf,0,_net.rxlen);
  174.                 _net.SendString("AT+CIPSEND\r\n");//开始处于透传发送状态
  175.                 if(FindStr((char*)_net.rxbuf,">",200)!=0)
  176.                 {
  177.                         return 1;
  178.                 }
  179.         }
  180.         return 0;
  181. }

  182. /**
  183. * 功能:主动和服务器断开连接
  184. * 参数:None
  185. * 返回值:
  186. *         连接结果,非0断开成功,0断开失败
  187. */
  188. static u8 DisconnectServer(void)
  189. {
  190.         u8 cnt;
  191.     _net.CloseTransmission();        //退出透传
  192.     Delay_ms(500);
  193.         while(cnt--)
  194.         {
  195.                 memset(_net.rxbuf,0,_net.rxlen);  
  196.                 _net.SendString("AT+CIPCLOSE\r\n");//关闭链接

  197.                 if(FindStr((char*)_net.rxbuf,"CLOSED",200)!=0)//操作成功,和服务器成功断开
  198.                 {
  199.                         break;
  200.                 }
  201.         }
  202.         if(cnt) return 1;
  203.         return 0;
  204. }

  205. /**
  206. * 功能:透传模式下的数据发送函数
  207. * 参数:
  208. *      buffer:待发送数据
  209. * 返回值:None
  210. */
  211. static void SendBuf(u8* buf,u16 len)
  212. {
  213.     memset(_net.rxbuf,0,_net.rxlen);
  214.         #ifdef _DEBUG_NET
  215.         Usart1_SendBuf(buf,len);
  216.         #endif        
  217.         Net_SendBuf(buf,len);
  218. }


  219. /**
  220. * 功能:透传模式下的数据发送函数
  221. * 参数:
  222. *      buffer:待发送数据
  223. * 返回值:None
  224. */
  225. static void SendString(char* str)
  226. {
  227.     memset(_net.rxbuf,0,_net.rxlen);
  228.         #ifdef _DEBUG_NET
  229.         Usart1_SendString(str);
  230.         #endif        
  231.         Net_SendString(str);
  232. }

  233. static u8 OpenTransmission(void)
  234. {
  235.         //设置透传模式
  236.         u8 cnt=2;
  237.         while(cnt--)
  238.         {
  239.         memset(_net.rxbuf,0,_net.rxlen);   
  240.         _net.SendString("AT+CIPMODE=1\r\n");  
  241.         if(FindStr((char*)_net.rxbuf,"OK",200)!=0)
  242.         {        
  243.                         return 1;
  244.                 }                        
  245.         }
  246.         return 0;
  247. }
  248. //退出透传
  249. static void CloseTransmission(void)
  250. {
  251.         _net.SendString("+++"); Delay_ms(50);
  252.         _net.SendString("+++"); Delay_ms(50);
  253. }

  254. /*********************************************END OF FILE********************************************/
复制代码

net.h部分

  1. #ifndef __FY_NETWORK_H
  2. #define __FY_NETWORK_H

  3. #include "fy_includes.h"

  4. /*连接AP宏定义*/
  5. #define SSID "ssid"
  6. #define PWD  "password"

  7. /*连接服务器宏定义*/
  8. #define TCP "TCP"
  9. #define UDP "UDP"
  10. #define IP  "122.114.122.174"
  11. #define PORT 40915

  12. #define Net_SendString(str) Usart2_SendString(str)
  13. #define Net_SendBuf(buf,len) Usart2_SendBuf(buf,len)

  14. typedef struct
  15. {
  16.         u8 *rxbuf;u16 rxlen;
  17.         u8 *txbuf;u16 txlen;
  18.         
  19.         u8 (*Check)(void);
  20.         u8 (*Init)(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);
  21.         void (*Restore)(void);
  22.         u8 (*ConnectAP)(char *ssid,char *pswd);
  23.         u8 (*ConnectServer)(char* mode,char *ip,u16 port);
  24.         u8 (*DisconnectServer)(void);
  25.         u8 (*OpenTransmission)(void);
  26.         void (*CloseTransmission)(void);               
  27.         void (*SendString)(char *str);
  28.         void (*SendBuf)(u8 *buf,u16 len);
  29. }_typdef_net;

  30. extern _typdef_net _net;

  31. #endif

  32. /*********************************************END OF FILE********************************************/
复制代码

mqtt.c部分
  1. #include "fy_mqtt.h"

  2. //#define _DEBUG_MQTT

  3. typedef enum
  4. {
  5.         //名字             值                         报文流动方向         描述
  6.         M_RESERVED1        =0        ,        //        禁止        保留
  7.         M_CONNECT                ,        //        客户端到服务端        客户端请求连接服务端
  8.         M_CONNACK                ,        //        服务端到客户端        连接报文确认
  9.         M_PUBLISH                ,        //        两个方向都允许        发布消息
  10.         M_PUBACK                ,        //        两个方向都允许        QoS 1消息发布收到确认
  11.         M_PUBREC                ,        //        两个方向都允许        发布收到(保证交付第一步)
  12.         M_PUBREL                ,        //        两个方向都允许        发布释放(保证交付第二步)
  13.         M_PUBCOMP                ,        //        两个方向都允许        QoS 2消息发布完成(保证交互第三步)
  14.         M_SUBSCRIBE                ,        //        客户端到服务端        客户端订阅请求
  15.         M_SUBACK                ,        //        服务端到客户端        订阅请求报文确认
  16.         M_UNSUBSCRIBE        ,        //        客户端到服务端        客户端取消订阅请求
  17.         M_UNSUBACK                ,        //        服务端到客户端        取消订阅报文确认
  18.         M_PINGREQ                ,        //        客户端到服务端        心跳请求
  19.         M_PINGRESP                ,        //        服务端到客户端        心跳响应
  20.         M_DISCONNECT        ,        //        客户端到服务端        客户端断开连接
  21.         M_RESERVED2                ,        //        禁止        保留
  22. }_typdef_mqtt_message;



  23. //连接成功服务器回应 20 02 00 00
  24. //客户端主动断开连接 e0 00
  25. const u8 parket_connetAck[] = {0x20,0x02,0x00,0x00};
  26. const u8 parket_disconnet[] = {0xe0,0x00};
  27. const u8 parket_heart[] = {0xc0,0x00};
  28. const u8 parket_heart_reply[] = {0xc0,0x00};
  29. const u8 parket_subAck[] = {0x90,0x03};

  30. static void Mqtt_SendBuf(u8 *buf,u16 len);

  31. static void Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);
  32. static u8 Connect(char *ClientID,char *Username,char *Password);
  33. static u8 SubscribeTopic(char *topic,u8 qos,u8 whether);
  34. static u8 PublishData(char *topic, char *message, u8 qos);
  35. static void SentHeart(void);
  36. static void Disconnect(void);

  37. _typdef_mqtt _mqtt =
  38. {
  39.         0,0,
  40.         0,0,
  41.         Init,
  42.         Connect,
  43.         SubscribeTopic,
  44.         PublishData,
  45.         SentHeart,
  46.         Disconnect,
  47. };

  48. static void Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen)
  49. {
  50.         _mqtt.rxbuf = prx;_mqtt.rxlen = rxlen;
  51.         _mqtt.txbuf = ptx;_mqtt.txlen = txlen;
  52.         
  53.         memset(_mqtt.rxbuf,0,_mqtt.rxlen);
  54.         memset(_mqtt.txbuf,0,_mqtt.txlen);
  55.         
  56.         //无条件先主动断开
  57.         _mqtt.Disconnect();Delay_ms(100);
  58.         _mqtt.Disconnect();Delay_ms(100);
  59. }


  60. //连接服务器的打包函数
  61. static u8 Connect(char *ClientID,char *Username,char *Password)
  62. {
  63.     int ClientIDLen = strlen(ClientID);
  64.     int UsernameLen = strlen(Username);
  65.     int PasswordLen = strlen(Password);
  66.     int DataLen;
  67.         _mqtt.txlen=0;
  68.         //可变报头+Payload  每个字段包含两个字节的长度标识
  69.     DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
  70.         
  71.         //固定报头
  72.         //控制报文类型
  73.     _mqtt.txbuf[_mqtt.txlen++] = 0x10;                //MQTT Message Type CONNECT
  74.         //剩余长度(不包括固定头部)
  75.         do
  76.         {
  77.                 u8 encodedByte = DataLen % 128;
  78.                 DataLen = DataLen / 128;
  79.                 // if there are more data to encode, set the top bit of this byte
  80.                 if ( DataLen > 0 )
  81.                         encodedByte = encodedByte | 128;
  82.                 _mqtt.txbuf[_mqtt.txlen++] = encodedByte;
  83.         }while ( DataLen > 0 );
  84.             
  85.         //可变报头
  86.         //协议名
  87.     _mqtt.txbuf[_mqtt.txlen++] = 0;                        // Protocol Name Length MSB   
  88.     _mqtt.txbuf[_mqtt.txlen++] = 4;                        // Protocol Name Length LSB   
  89.     _mqtt.txbuf[_mqtt.txlen++] = 'M';                // ASCII Code for M   
  90.     _mqtt.txbuf[_mqtt.txlen++] = 'Q';                // ASCII Code for Q   
  91.     _mqtt.txbuf[_mqtt.txlen++] = 'T';                // ASCII Code for T   
  92.     _mqtt.txbuf[_mqtt.txlen++] = 'T';                // ASCII Code for T   
  93.         //协议级别
  94.     _mqtt.txbuf[_mqtt.txlen++] = 4;                        // MQTT Protocol version = 4   
  95.         //连接标志
  96.     _mqtt.txbuf[_mqtt.txlen++] = 0xc2;                // conn flags
  97.     _mqtt.txbuf[_mqtt.txlen++] = 0;                        // Keep-alive Time Length MSB   
  98.     _mqtt.txbuf[_mqtt.txlen++] = 60;                // Keep-alive Time Length LSB  60S心跳包  
  99.         
  100.     _mqtt.txbuf[_mqtt.txlen++] = BYTE1(ClientIDLen);// Client ID length MSB   
  101.     _mqtt.txbuf[_mqtt.txlen++] = BYTE0(ClientIDLen);// Client ID length LSB         
  102.         memcpy(&_mqtt.txbuf[_mqtt.txlen],ClientID,ClientIDLen);
  103.     _mqtt.txlen += ClientIDLen;

  104.     if(UsernameLen > 0)
  105.     {   
  106.         _mqtt.txbuf[_mqtt.txlen++] = BYTE1(UsernameLen);                //username length MSB   
  107.         _mqtt.txbuf[_mqtt.txlen++] = BYTE0(UsernameLen);            //username length LSB   
  108.                 memcpy(&_mqtt.txbuf[_mqtt.txlen],Username,UsernameLen);
  109.         _mqtt.txlen += UsernameLen;
  110.     }

  111.     if(PasswordLen > 0)
  112.     {   
  113.         _mqtt.txbuf[_mqtt.txlen++] = BYTE1(PasswordLen);                //password length MSB   
  114.         _mqtt.txbuf[_mqtt.txlen++] = BYTE0(PasswordLen);            //password length LSB  
  115.                 memcpy(&_mqtt.txbuf[_mqtt.txlen],Password,PasswordLen);
  116.         _mqtt.txlen += PasswordLen;
  117.     }   
  118.         
  119.         u8 cnt=2;
  120.         u8 wait;
  121.         while(cnt--)
  122.         {
  123.                 memset(_mqtt.rxbuf,0,_mqtt.rxlen);
  124.                 Mqtt_SendBuf(_mqtt.txbuf,_mqtt.txlen);
  125.                 wait=30;//等待3s时间
  126.                 while(wait--)
  127.                 {
  128.                         //CONNECT
  129.                         if(_mqtt.rxbuf[0]==parket_connetAck[0] && _mqtt.rxbuf[1]==parket_connetAck[1]) //连接成功                           
  130.                         {
  131.                                 return 1;//连接成功
  132.                         }
  133.                         Delay_ms(100);                        
  134.                 }
  135.         }
  136.         return 0;
  137. }


  138. //MQTT订阅/取消订阅数据打包函数
  139. //topic       主题
  140. //qos         消息等级
  141. //whether     订阅/取消订阅请求包
  142. static u8 SubscribeTopic(char *topic,u8 qos,u8 whether)
  143. {   
  144.         _mqtt.txlen=0;
  145.     int topiclen = strlen(topic);
  146.         
  147.         int DataLen = 2 + (topiclen+2) + (whether?1:0);//可变报头的长度(2字节)加上有效载荷的长度
  148.         //固定报头
  149.         //控制报文类型
  150.     if(whether) _mqtt.txbuf[_mqtt.txlen++] = 0x82; //消息类型和标志订阅
  151.     else        _mqtt.txbuf[_mqtt.txlen++] = 0xA2;    //取消订阅

  152.         //剩余长度
  153.         do
  154.         {
  155.                 u8 encodedByte = DataLen % 128;
  156.                 DataLen = DataLen / 128;
  157.                 // if there are more data to encode, set the top bit of this byte
  158.                 if ( DataLen > 0 )
  159.                         encodedByte = encodedByte | 128;
  160.                 _mqtt.txbuf[_mqtt.txlen++] = encodedByte;
  161.         }while ( DataLen > 0 );        
  162.         
  163.         //可变报头
  164.     _mqtt.txbuf[_mqtt.txlen++] = 0;                                //消息标识符 MSB
  165.     _mqtt.txbuf[_mqtt.txlen++] = 0x01;           //消息标识符 LSB
  166.         //有效载荷
  167.     _mqtt.txbuf[_mqtt.txlen++] = BYTE1(topiclen);//主题长度 MSB
  168.     _mqtt.txbuf[_mqtt.txlen++] = BYTE0(topiclen);//主题长度 LSB   
  169.         memcpy(&_mqtt.txbuf[_mqtt.txlen],topic,topiclen);
  170.     _mqtt.txlen += topiclen;

  171.     if(whether)
  172.     {
  173.         _mqtt.txbuf[_mqtt.txlen++] = qos;//QoS级别
  174.     }
  175.         
  176.         u8 cnt=2;
  177.         u8 wait;
  178.         while(cnt--)
  179.         {
  180.                 memset(_mqtt.rxbuf,0,_mqtt.rxlen);
  181.                 Mqtt_SendBuf(_mqtt.txbuf,_mqtt.txlen);
  182.                 wait=30;//等待3s时间
  183.                 while(wait--)
  184.                 {
  185.                         if(_mqtt.rxbuf[0]==parket_subAck[0] && _mqtt.rxbuf[1]==parket_subAck[1]) //订阅成功                           
  186.                         {
  187.                                 return 1;//订阅成功
  188.                         }
  189.                         Delay_ms(100);                        
  190.                 }
  191.         }
  192.         if(cnt) return 1;        //订阅成功
  193.         return 0;
  194. }

  195. //MQTT发布数据打包函数
  196. //topic   主题
  197. //message 消息
  198. //qos     消息等级
  199. static u8 PublishData(char *topic, char *message, u8 qos)
  200. {  
  201.     int topicLength = strlen(topic);   
  202.     int messageLength = strlen(message);     
  203.     static u16 id=0;
  204.         int DataLen;
  205.         _mqtt.txlen=0;
  206.         //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
  207.         //QOS为0时没有标识符
  208.         //数据长度             主题名   报文标识符   有效载荷
  209.     if(qos)        DataLen = (2+topicLength) + 2 + messageLength;      
  210.     else        DataLen = (2+topicLength) + messageLength;   

  211.     //固定报头
  212.         //控制报文类型
  213.     _mqtt.txbuf[_mqtt.txlen++] = 0x30;    // MQTT Message Type PUBLISH  

  214.         //剩余长度
  215.         do
  216.         {
  217.                 u8 encodedByte = DataLen % 128;
  218.                 DataLen = DataLen / 128;
  219.                 // if there are more data to encode, set the top bit of this byte
  220.                 if ( DataLen > 0 )
  221.                         encodedByte = encodedByte | 128;
  222.                 _mqtt.txbuf[_mqtt.txlen++] = encodedByte;
  223.         }while ( DataLen > 0 );        
  224.         
  225.     _mqtt.txbuf[_mqtt.txlen++] = BYTE1(topicLength);//主题长度MSB
  226.     _mqtt.txbuf[_mqtt.txlen++] = BYTE0(topicLength);//主题长度LSB
  227.         memcpy(&_mqtt.txbuf[_mqtt.txlen],topic,topicLength);//拷贝主题
  228.     _mqtt.txlen += topicLength;

  229.         //报文标识符
  230.     if(qos)
  231.     {
  232.         _mqtt.txbuf[_mqtt.txlen++] = BYTE1(id);
  233.         _mqtt.txbuf[_mqtt.txlen++] = BYTE0(id);
  234.         id++;
  235.     }
  236.         memcpy(&_mqtt.txbuf[_mqtt.txlen],message,messageLength);
  237.     _mqtt.txlen += messageLength;

  238.         Mqtt_SendBuf(_mqtt.txbuf,_mqtt.txlen);
  239.     return _mqtt.txlen;
  240. }

  241. static void SentHeart(void)
  242. {
  243.         Mqtt_SendBuf((u8 *)parket_heart,sizeof(parket_heart));
  244. }

  245. static void Disconnect(void)
  246. {
  247.         Mqtt_SendBuf((u8 *)parket_disconnet,sizeof(parket_disconnet));
  248. }

  249. static void Mqtt_SendBuf(u8 *buf,u16 len)
  250. {
  251.         #ifdef _DEBUG_MQTT
  252.         Usart1_SendBuf(buf,len);
  253.         #endif
  254.         Usart2_SendBuf(buf,len);
  255. }        

  256. /*********************************************END OF FILE********************************************/
复制代码

mqtt.h部分

  1. #ifndef __FY_MQTT_H_
  2. #define __FY_MQTT_H_

  3. #include "fy_includes.h"



  4. typedef struct
  5. {
  6.         u8 *rxbuf;u16 rxlen;
  7.         u8 *txbuf;u16 txlen;
  8.         void (*Init)(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);
  9.         u8 (*Connect)(char *ClientID,char *Username,char *Password);
  10.         u8 (*SubscribeTopic)(char *topic,u8 qos,u8 whether);
  11.         u8 (*PublishData)(char *topic, char *message, u8 qos);
  12.         void (*SendHeart)(void);
  13.         void (*Disconnect)(void);
  14. }_typdef_mqtt;

  15. extern _typdef_mqtt _mqtt;

  16. #endif
复制代码





收藏 评论0 发布时间:2022-3-16 11:31

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版