【单片机笔记】STM32+ESP8266通过AT指令WIFI连接阿里云MQTT服务器

        上一篇使用USB转串口的方式通过ESP8266wifi模块的方式成功连接上了阿里云,现在就要通过单片机来替换电脑上位机了,这样单片机自动的去调用并发送串口数据更加方便,也更加符合一个产品的开发。板载的传感器有NTC温度,光强,这两个主要用来设备上传到平台,另外一个是RGB的灯,这个主要是用来平台下发设备的接收和解析。这里为了直观我直接用串口打印出来。只要数据部分对了其他的都好说。
网页上的运行状态图

温度曲线图

光强曲线图

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

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

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

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

main.c部分

#include "fy_includes.h"#include "fy_tlink.h"/*晶振使用的是16M 其他频率在system_stm32f10x.c中修改使用printf需要在fy_includes.h修改串口重定向为#define PRINTF_USART USART1 */ _typdef_adc _adc;u16 adc_light;u16 adc_ntc;u16 battery;float temperature;u8 led_sta;u8 sta;void Adc_GetValue(void); u8 txbuf[256];u8 rxbuf[256]; char mqtt_message[200];  void Mqtt_Progress(u8 *buf,u16 len); void UsartTrance(void){    while(1)    {       Led_Tog();      Delay_ms(500);  }} int main(void){  u8 cnt_2s=0;    u16 cnt_5s=0;   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    Systick_Configuration();    Led_Configuration();//   UsartTrance();  Key_Configuration();    Adc_Configuration();    Adc_DMA_Configuration((u32)&_adc.buf,ADC_FILTER*ADC_CH_MAX);    Usart1_Configuration(115200);   Usart2_Configuration(115200);   Oled_Configuration();   Usart1_SendString("  usart1 is ok!\r\n");// Usart2_SendString("  usart2 is ok!\r\n");   Delay_ms(200);  //  UsartTrance();  sta=0;      //检查ESP8266    if(_net.Init(rxbuf,sizeof(rxbuf),txbuf,sizeof(txbuf))!=0){       Oled_ShowString(0,0*16,"Net Init OK!",8,16,1);//        printf("Net Init OK!\r\n");     sta++;  }   else{       Oled_ShowString(0,0*16,"Net Init Error!",8,16,1);//     printf("Net Init Error!\r\n");      sta=0;  }   Oled_RefreshGram();     if(sta==1){     //连接热点      if(_net.ConnectAP("ssid","password")!=0){           Oled_ShowString(0,1*16,"Conncet AP OK!",8,16,1);//          printf("Conncet AP OK!\r\n");           sta++;      }       else {          Oled_ShowString(0,1*16,"Conncet AP Error!",8,16,1);//           printf("Conncet AP Error!\r\n");            sta=0;      }       Oled_RefreshGram(); }       if(sta==2){         //连接TCP     if(_net.ConnectServer("TCP","a1ugBNniFGU.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883)!=0) {          Oled_ShowString(0,2*16,"Conet Server OK!",8,16,1);//            printf("Conncet Server OK!\r\n");           sta++;      }       else{           Oled_ShowString(0,2*16,"Server Error!",8,16,1);//           printf("Conncet Server Error!\r\n");                sta=0;      }       Oled_RefreshGram(); }       if(sta==3){     //登录MQTT        _mqtt.Init(rxbuf,sizeof(rxbuf),txbuf,sizeof(txbuf));                if(_mqtt.Connect(           "123456|securemode=3,signmethod=hmacsha1,timestamp=789|",//ClientID         "FY-STM32&a1ugBNniFGU",//Username           "b447b9f26938d8eba6b2a4878066aae91839600c"//Password            ) != 0){            Oled_ShowString(0,3*16,"Enter MQTT OK!",8,16,1);//          printf("Enter MQTT OK!\r\n");           sta++;      }       else{                   Oled_ShowString(0,3*16,"Enter MQTT Error",8,16,1);//            printf("Enter MQTT Error!\r\n");            sta=0;      }           Oled_RefreshGram(); }           if(sta==4){     Oled_Clear();       //订阅主题      if(_mqtt.SubscribeTopic("/sys/a1ugBNniFGU/FY-STM32/thing/service/property/set",0,1) != 0){          Oled_ShowString(0,0*16,"Subscribe OK!",8,16,1);//           printf("SubscribeTopic OK!\r\n");       }       else{                       Oled_ShowString(0,0*16,"Subscribe Error!",8,16,1);//            printf("SubscribeTopic Error!\r\n");        }       Oled_RefreshGram();         }   Delay_ms(1000); Oled_Clear();               Oled_ShowString(32,0*16,"Mars Tech",8,16,1);    Oled_ShowString(0,1*16," VCC: 0000 mV",8,16,1); Oled_ShowString(0,2*16,"Temp: 00.0 C",8,16,1);  Oled_ShowString(0,3*16," LUX: 0000  ",8,16,1);  Oled_RefreshGram(); sta = 0;    while(1)    {       if(++cnt_2s>=200){          cnt_2s=0;           Adc_GetValue();         temperature = Ntc_GetTemp(adc_ntc)*0.1f;            Oled_ShowNum(8*6,1*16,battery,4,8,16);                      Oled_ShowNum(8*6,2*16,(u8)temperature,2,8,16);          Oled_ShowNum(8*6+3*8,2*16,(u16)(temperature*10)%10,1,8,16);                     Oled_ShowNum(8*6,3*16,adc_light,4,8,16);                        Oled_RefreshGram();     }       if(++cnt_5s>=500){//            cnt_5s=0;           sprintf(mqtt_message,           "{\"method\":\"thing.service.property.set\",\"id\":\"630262306\",\"params\":{\              \"CurrentTemperature\":%.1f,\               \"hue\":%d,\                \"mlux\":%d\            },\"version\":\"1.0.0\"}",          temperature,            rand()%0x00ffffff,          adc_light           );                      _mqtt.PublishData("/sys/a1ugBNniFGU/FY-STM32/thing/event/property/post",mqtt_message,0);                    }       if(_mqtt.rxlen){            Mqtt_Progress(_mqtt.rxbuf,_mqtt.rxlen);                 memset(_mqtt.rxbuf,0,_mqtt.rxlen);          _mqtt.rxlen = 0;        }                   Delay_ms(10);     }} void Adc_GetValue(void){   u32 sum[ADC_CH_MAX];        memset(sum,0,sizeof(sum));  for(u8 ch=0; chDR;//        USART1->DR = temp;//这里用作串口1打印WIFI模块发送的数据        if(rxlen>=255) rxlen=0;        rxbuf[rxlen++] = temp;        rxlen%=sizeof(rxbuf);    }     if(USART_GetITStatus(USART2, USART_IT_IDLE))    {       temp = USART2->DR;      temp = USART2->SR;      _mqtt.rxlen = rxlen;//      Mqtt_Progress(rxbuf,rxlen);//主循环做异步处理       rxlen=0;    }}//void *StrStr(void *dest,void *src); u8 *p;void Mqtt_Progress(u8 *buf,u16 len){  char *keyStr = "hue";   u8 keyStrLen = strlen(keyStr)-1;    u8 i,j; for(i=0;i

net.c部分

#include "fy_network.h" //#define _DEBUG_NET static u8 Check(void);static u8 Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);static void Restore(void);static u8 ConnectAP(char* ssid,char* pswd);static u8 ConnectServer(char* mode,char* ip,u16 port);static u8 DisconnectServer(void);static u8 OpenTransmission(void);static void CloseTransmission(void);static void SendString(char* str);static void SendBuf(u8* buf,u16 len);  _typdef_net _net={    0,0,    0,0,    Check,  Init,   Restore,    ConnectAP,  ConnectServer,  DisconnectServer,   OpenTransmission,   CloseTransmission,  SendString, SendBuf}; /** * 功能:初始化ESP8266 * 参数:None * 返回值:初始化结果,非0为初始化成功,0为失败 */static u8 Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen){    _net.rxbuf = prx;_net.rxlen = rxlen;    _net.txbuf = ptx;_net.txlen = txlen;        memset(_net.rxbuf,0,_net.rxlen);    memset(_net.txbuf,0,_net.txlen);        _net.CloseTransmission();          //退出透传     Delay_ms(500);    _net.SendString("AT+RST\r\n");   //重启ESP8266    Delay_ms(800);    if(_net.Check()==0)              //使用AT指令检查ESP8266是否存在    {        return 0;    }     memset(_net.rxbuf,0,_net.rxlen);    //清空接收缓冲    _net.SendString("ATE0\r\n");        //关闭回显     if(FindStr((char*)_net.rxbuf,"OK",500)==0)  //设置不成功    {        return 0;          }    return 1;                         //设置成功 } /** * 功能:恢复出厂设置 * 参数:None * 返回值:None * 说明:此时ESP8266中的用户设置将全部丢失回复成出厂状态 */static void Restore(void){    _net.CloseTransmission();           //退出透传    Delay_ms(500);    _net.SendString("AT+RESTORE\r\n");//恢复出厂    //    NVIC_SystemReset();                 //同时重启单片机   } /** * 功能:检查ESP8266是否正常 * 参数:None * 返回值:ESP8266返回状态 *        非0 ESP8266正常 *        0 ESP8266有问题   */static u8 Check(void){   u8 check_cnt=5; while(check_cnt--)  {       memset(_net.rxbuf,0,_net.rxlen);     //清空接收缓冲       _net.SendString("AT\r\n");           //发送AT握手指令         if(FindStr((char*)_net.rxbuf,"OK",200) != 0)        {           return 1;       }   }   return 0;} /** * 功能:连接热点 * 参数: *         ssid:热点名 *         pwd:热点密码 * 返回值: *         连接结果,非0连接成功,0连接失败 * 说明:  *         失败的原因有以下几种(UART通信和ESP8266正常情况下) *         1. WIFI名和密码不正确 *         2. 路由器连接设备太多,未能给ESP8266分配IP */static u8 ConnectAP(char* ssid,char* pswd){   u8 cnt=5;   while(cnt--)    {       memset(_net.rxbuf,0,_net.rxlen);            _net.SendString("AT+CWMODE_CUR=1\r\n");              //设置为STATION模式         if(FindStr((char*)_net.rxbuf,"OK",200) != 0)        {           break;      }                       }   if(cnt == 0)        return 0;   cnt=2;  while(cnt--)    {       memset(_net.txbuf,0,_net.txlen);                            //清空发送缓冲        memset(_net.rxbuf,0,_net.rxlen);                            //清空接收缓冲        sprintf((char*)_net.txbuf,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pswd);//连接目标AP      _net.SendString((char*)_net.txbuf);         if(FindStr((char*)_net.rxbuf,"OK",8000)!=0)                      //连接成功且分配到IP       {           return 1;       }   }   return 0;} /** * 功能:使用指定协议(TCP/UDP)连接到服务器 * 参数: *         mode:协议类型 "TCP","UDP" *         ip:目标服务器IP *         port:目标是服务器端口号 * 返回值: *         连接结果,非0连接成功,0连接失败 * 说明:  *         失败的原因有以下几种(UART通信和ESP8266正常情况下) *         1. 远程服务器IP和端口号有误 *         2. 未连接AP *         3. 服务器端禁止添加(一般不会发生) */static u8 ConnectServer(char* mode,char* ip,u16 port){  u8 cnt;       _net.CloseTransmission();                   //多次连接需退出透传    Delay_ms(500);     //连接服务器 cnt=2;  while(cnt--)    {       memset(_net.rxbuf,0,_net.rxlen);            memset(_net.txbuf,0,_net.txlen);        sprintf((char*)_net.txbuf,"AT+CIPSTART=\"%s\",\"%s\",%d\r\n",mode,ip,port);     _net.SendString((char*)_net.txbuf);     if(FindStr((char*)_net.rxbuf,"CONNECT",8000) !=0 )      {           break;      }   }   if(cnt == 0)        return 0;       //设置透传模式    if(_net.OpenTransmission()==0) return 0;        //开启发送状态    cnt=2;  while(cnt--)    {       memset(_net.rxbuf,0,_net.rxlen);        _net.SendString("AT+CIPSEND\r\n");//开始处于透传发送状态      if(FindStr((char*)_net.rxbuf,">",200)!=0)       {           return 1;       }   }   return 0;} /** * 功能:主动和服务器断开连接 * 参数:None * 返回值: *         连接结果,非0断开成功,0断开失败 */static u8 DisconnectServer(void){ u8 cnt;    _net.CloseTransmission();    //退出透传    Delay_ms(500);    while(cnt--)    {       memset(_net.rxbuf,0,_net.rxlen);        _net.SendString("AT+CIPCLOSE\r\n");//关闭链接       if(FindStr((char*)_net.rxbuf,"CLOSED",200)!=0)//操作成功,和服务器成功断开       {           break;      }   }   if(cnt) return 1;   return 0;} /** * 功能:透传模式下的数据发送函数 * 参数: *      buffer:待发送数据 * 返回值:None */static void SendBuf(u8* buf,u16 len){    memset(_net.rxbuf,0,_net.rxlen);   #ifdef _DEBUG_NET   Usart1_SendBuf(buf,len);    #endif      Net_SendBuf(buf,len);}  /** * 功能:透传模式下的数据发送函数 * 参数: *      buffer:待发送数据 * 返回值:None */static void SendString(char* str){    memset(_net.rxbuf,0,_net.rxlen); #ifdef _DEBUG_NET   Usart1_SendString(str); #endif      Net_SendString(str);} static u8 OpenTransmission(void){ //设置透传模式    u8 cnt=2;   while(cnt--)    {        memset(_net.rxbuf,0,_net.rxlen);            _net.SendString("AT+CIPMODE=1\r\n");          if(FindStr((char*)_net.rxbuf,"OK",200)!=0)        {              return 1;       }               }   return 0;}//退出透传static void CloseTransmission(void){    _net.SendString("+++"); Delay_ms(50);   _net.SendString("+++"); Delay_ms(50);} /*********************************************END OF FILE********************************************/ 

net.h部分

#ifndef __FY_NETWORK_H#define __FY_NETWORK_H #include "fy_includes.h" /*连接AP宏定义*/#define SSID "ssid"#define PWD  "password" /*连接服务器宏定义*/#define TCP "TCP"#define UDP "UDP"#define IP  "122.114.122.174"#define PORT 40915 #define Net_SendString(str) Usart2_SendString(str)#define Net_SendBuf(buf,len) Usart2_SendBuf(buf,len) typedef struct{    u8 *rxbuf;u16 rxlen;    u8 *txbuf;u16 txlen;        u8 (*Check)(void);  u8 (*Init)(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);    void (*Restore)(void);  u8 (*ConnectAP)(char *ssid,char *pswd); u8 (*ConnectServer)(char* mode,char *ip,u16 port);  u8 (*DisconnectServer)(void);   u8 (*OpenTransmission)(void);   void (*CloseTransmission)(void);            void (*SendString)(char *str);  void (*SendBuf)(u8 *buf,u16 len);}_typdef_net; extern _typdef_net _net; #endif /*********************************************END OF FILE********************************************/ 

mqtt.c部分

#include "fy_mqtt.h" //#define _DEBUG_MQTT typedef enum{    //名字        值           报文流动方向  描述  M_RESERVED1 =0  ,   //  禁止  保留  M_CONNECT       ,   //  客户端到服务端 客户端请求连接服务端  M_CONNACK       ,   //  服务端到客户端 连接报文确认  M_PUBLISH       ,   //  两个方向都允许 发布消息    M_PUBACK        ,   //  两个方向都允许 QoS 1消息发布收到确认   M_PUBREC        ,   //  两个方向都允许 发布收到(保证交付第一步)   M_PUBREL        ,   //  两个方向都允许 发布释放(保证交付第二步)   M_PUBCOMP       ,   //  两个方向都允许 QoS 2消息发布完成(保证交互第三步)    M_SUBSCRIBE     ,   //  客户端到服务端 客户端订阅请求 M_SUBACK        ,   //  服务端到客户端 订阅请求报文确认    M_UNSUBSCRIBE   ,   //  客户端到服务端 客户端取消订阅请求   M_UNSUBACK      ,   //  服务端到客户端 取消订阅报文确认    M_PINGREQ       ,   //  客户端到服务端 心跳请求    M_PINGRESP      ,   //  服务端到客户端 心跳响应    M_DISCONNECT    ,   //  客户端到服务端 客户端断开连接 M_RESERVED2     ,   //  禁止  保留}_typdef_mqtt_message;   //连接成功服务器回应 20 02 00 00//客户端主动断开连接 e0 00const u8 parket_connetAck[] = {0x20,0x02,0x00,0x00};const u8 parket_disconnet[] = {0xe0,0x00};const u8 parket_heart[] = {0xc0,0x00};const u8 parket_heart_reply[] = {0xc0,0x00};const u8 parket_subAck[] = {0x90,0x03}; static void Mqtt_SendBuf(u8 *buf,u16 len); static void Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);static u8 Connect(char *ClientID,char *Username,char *Password);static u8 SubscribeTopic(char *topic,u8 qos,u8 whether);static u8 PublishData(char *topic, char *message, u8 qos);static void SentHeart(void);static void Disconnect(void); _typdef_mqtt _mqtt = {  0,0,    0,0,    Init,   Connect,    SubscribeTopic, PublishData,    SentHeart,  Disconnect,}; static void Init(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen){    _mqtt.rxbuf = prx;_mqtt.rxlen = rxlen;  _mqtt.txbuf = ptx;_mqtt.txlen = txlen;      memset(_mqtt.rxbuf,0,_mqtt.rxlen);  memset(_mqtt.txbuf,0,_mqtt.txlen);      //无条件先主动断开  _mqtt.Disconnect();Delay_ms(100);   _mqtt.Disconnect();Delay_ms(100);}  //连接服务器的打包函数static u8 Connect(char *ClientID,char *Username,char *Password){    int ClientIDLen = strlen(ClientID);    int UsernameLen = strlen(Username);    int PasswordLen = strlen(Password);    int DataLen;   _mqtt.txlen=0;  //可变报头+Payload  每个字段包含两个字节的长度标识    DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);      //固定报头  //控制报文类型    _mqtt.txbuf[_mqtt.txlen++] = 0x10;      //MQTT Message Type CONNECT //剩余长度(不包括固定头部) do  {       u8 encodedByte = DataLen % 128;     DataLen = DataLen / 128;        // if there are more data to encode, set the top bit of this byte       if ( DataLen > 0 )          encodedByte = encodedByte | 128;        _mqtt.txbuf[_mqtt.txlen++] = encodedByte;   }while ( DataLen > 0 );         //可变报头  //协议名    _mqtt.txbuf[_mqtt.txlen++] = 0;                // Protocol Name Length MSB        _mqtt.txbuf[_mqtt.txlen++] = 4;              // Protocol Name Length LSB        _mqtt.txbuf[_mqtt.txlen++] = 'M';            // ASCII Code for M        _mqtt.txbuf[_mqtt.txlen++] = 'Q';            // ASCII Code for Q        _mqtt.txbuf[_mqtt.txlen++] = 'T';            // ASCII Code for T        _mqtt.txbuf[_mqtt.txlen++] = 'T';            // ASCII Code for T     //协议级别    _mqtt.txbuf[_mqtt.txlen++] = 4;               // MQTT Protocol version = 4        //连接标志    _mqtt.txbuf[_mqtt.txlen++] = 0xc2;            // conn flags     _mqtt.txbuf[_mqtt.txlen++] = 0;               // Keep-alive Time Length MSB        _mqtt.txbuf[_mqtt.txlen++] = 60;           // Keep-alive Time Length LSB  60S心跳包       _mqtt.txbuf[_mqtt.txlen++] = BYTE1(ClientIDLen);// Client ID length MSB        _mqtt.txbuf[_mqtt.txlen++] = BYTE0(ClientIDLen);// Client ID length LSB          memcpy(&_mqtt.txbuf[_mqtt.txlen],ClientID,ClientIDLen);    _mqtt.txlen += ClientIDLen;        if(UsernameLen > 0)    {           _mqtt.txbuf[_mqtt.txlen++] = BYTE1(UsernameLen);       //username length MSB            _mqtt.txbuf[_mqtt.txlen++] = BYTE0(UsernameLen);       //username length LSB           memcpy(&_mqtt.txbuf[_mqtt.txlen],Username,UsernameLen);        _mqtt.txlen += UsernameLen;    }        if(PasswordLen > 0)    {            _mqtt.txbuf[_mqtt.txlen++] = BYTE1(PasswordLen);     //password length MSB            _mqtt.txbuf[_mqtt.txlen++] = BYTE0(PasswordLen);       //password length LSB       memcpy(&_mqtt.txbuf[_mqtt.txlen],Password,PasswordLen);        _mqtt.txlen += PasswordLen;     }            u8 cnt=2;   u8 wait;    while(cnt--)    {       memset(_mqtt.rxbuf,0,_mqtt.rxlen);      Mqtt_SendBuf(_mqtt.txbuf,_mqtt.txlen);      wait=30;//等待3s时间        while(wait--)       {           //CONNECT           if(_mqtt.rxbuf[0]==parket_connetAck[0] && _mqtt.rxbuf[1]==parket_connetAck[1]) //连接成功                       {               return 1;//连接成功         }           Delay_ms(100);                  }   }   return 0;}  //MQTT订阅/取消订阅数据打包函数//topic       主题 //qos         消息等级 //whether     订阅/取消订阅请求包static u8 SubscribeTopic(char *topic,u8 qos,u8 whether){     _mqtt.txlen=0;    int topiclen = strlen(topic);     int DataLen = 2 + (topiclen+2) + (whether?1:0);//可变报头的长度(2字节)加上有效载荷的长度  //固定报头  //控制报文类型    if(whether) _mqtt.txbuf[_mqtt.txlen++] = 0x82; //消息类型和标志订阅    else  _mqtt.txbuf[_mqtt.txlen++] = 0xA2;    //取消订阅    //剩余长度  do  {       u8 encodedByte = DataLen % 128;     DataLen = DataLen / 128;        // if there are more data to encode, set the top bit of this byte       if ( DataLen > 0 )          encodedByte = encodedByte | 128;        _mqtt.txbuf[_mqtt.txlen++] = encodedByte;   }while ( DataLen > 0 );         //可变报头    _mqtt.txbuf[_mqtt.txlen++] = 0;               //消息标识符 MSB    _mqtt.txbuf[_mqtt.txlen++] = 0x01;           //消息标识符 LSB //有效载荷    _mqtt.txbuf[_mqtt.txlen++] = BYTE1(topiclen);//主题长度 MSB    _mqtt.txbuf[_mqtt.txlen++] = BYTE0(topiclen);//主题长度 LSB    memcpy(&_mqtt.txbuf[_mqtt.txlen],topic,topiclen);    _mqtt.txlen += topiclen;        if(whether)    {        _mqtt.txbuf[_mqtt.txlen++] = qos;//QoS级别    }      u8 cnt=2;   u8 wait;    while(cnt--)    {       memset(_mqtt.rxbuf,0,_mqtt.rxlen);      Mqtt_SendBuf(_mqtt.txbuf,_mqtt.txlen);      wait=30;//等待3s时间        while(wait--)       {           if(_mqtt.rxbuf[0]==parket_subAck[0] && _mqtt.rxbuf[1]==parket_subAck[1]) //订阅成功                     {               return 1;//订阅成功         }           Delay_ms(100);                  }   }   if(cnt) return 1;   //订阅成功  return 0;} //MQTT发布数据打包函数//topic   主题 //message 消息//qos     消息等级 static u8 PublishData(char *topic, char *message, u8 qos){      int topicLength = strlen(topic);        int messageLength = strlen(message);         static u16 id=0;  int DataLen;    _mqtt.txlen=0;  //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度  //QOS为0时没有标识符   //数据长度             主题名   报文标识符   有效载荷    if(qos)    DataLen = (2+topicLength) + 2 + messageLength;           else   DataLen = (2+topicLength) + messageLength;        //固定报头    //控制报文类型    _mqtt.txbuf[_mqtt.txlen++] = 0x30;    // MQTT Message Type PUBLISH      //剩余长度  do  {       u8 encodedByte = DataLen % 128;     DataLen = DataLen / 128;        // if there are more data to encode, set the top bit of this byte       if ( DataLen > 0 )          encodedByte = encodedByte | 128;        _mqtt.txbuf[_mqtt.txlen++] = encodedByte;   }while ( DataLen > 0 );         _mqtt.txbuf[_mqtt.txlen++] = BYTE1(topicLength);//主题长度MSB    _mqtt.txbuf[_mqtt.txlen++] = BYTE0(topicLength);//主题长度LSB  memcpy(&_mqtt.txbuf[_mqtt.txlen],topic,topicLength);//拷贝主题    _mqtt.txlen += topicLength;           //报文标识符    if(qos)    {        _mqtt.txbuf[_mqtt.txlen++] = BYTE1(id);        _mqtt.txbuf[_mqtt.txlen++] = BYTE0(id);        id++;    } memcpy(&_mqtt.txbuf[_mqtt.txlen],message,messageLength);    _mqtt.txlen += messageLength;           Mqtt_SendBuf(_mqtt.txbuf,_mqtt.txlen);    return _mqtt.txlen;} static void SentHeart(void){ Mqtt_SendBuf((u8 *)parket_heart,sizeof(parket_heart));} static void Disconnect(void){   Mqtt_SendBuf((u8 *)parket_disconnet,sizeof(parket_disconnet));} static void Mqtt_SendBuf(u8 *buf,u16 len){  #ifdef _DEBUG_MQTT  Usart1_SendBuf(buf,len);    #endif  Usart2_SendBuf(buf,len);}    /*********************************************END OF FILE********************************************/

mqtt.h部分

#ifndef __FY_MQTT_H_#define __FY_MQTT_H_ #include "fy_includes.h"   typedef struct{    u8 *rxbuf;u16 rxlen;    u8 *txbuf;u16 txlen;    void (*Init)(u8 *prx,u16 rxlen,u8 *ptx,u16 txlen);  u8 (*Connect)(char *ClientID,char *Username,char *Password);    u8 (*SubscribeTopic)(char *topic,u8 qos,u8 whether);    u8 (*PublishData)(char *topic, char *message, u8 qos);  void (*SendHeart)(void);    void (*Disconnect)(void);}_typdef_mqtt; extern _typdef_mqtt _mqtt; #endif 

完整工程:https://download.csdn.net/download/qq997758497/11239490。

By Urien 2019年6月13日 14:59:29

你可能感兴趣的:(服务器,云服务器,云主机,云服务,云服务器,阿里云,腾讯云,华为云)