【单片机笔记】STM32+ESP8266通过AT指令WIFI连接阿里云MQTT服务器_stm32+esp8266+云服务器+qt上位机(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; ch<ADC_CH_MAX; ch++)   {       for(u8 filter=0; filter<ADC_FILTER; filter++)       {           sum[ch] += _adc.buf[filter][ch];//计算累加和     }           }   adc_light = sum[ADC_LIGHT]/ADC_FILTER;  adc_ntc = sum[ADC_NTC]/ADC_FILTER;  battery = sum[ADC_VCC]/ADC_FILTER*3300/4095*11;     //mV} u8 temp;void USART2_IRQHandler(void){    static u8 rxlen = 0;     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //判断接收数据寄存器是否有数据    {     temp = USART2->DR;//        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<len-keyStrLen;i++)    {       for(j=0;j<keyStrLen;j++)        {           if(buf[i+j] != keyStr[j])   break;      }           if(j==keyStrLen) break; }   if(i<=len-keyStrLen)    {       u16 temp = 0;       p = &buf[i];                        while(*p != ':') p++;       p++;        while(*p != '}')        {           temp = temp *10 + (*p - '0');           p++;        }       printf("receive message, hue = %d \r\n",temp);//        Usart1_SendBuf(buf,len);     }} /*********************************************END OF FILE********************************************/ 

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/NicolasLearner/article/details/113853219

智能推荐

maven配置本地仓库、maven配置阿里中央仓库_maven配置本地仓库路径-程序员宅基地

文章浏览阅读2.1k次。找到并修改< localRepository>,最初是注释掉的,取消注释就可以 < localRepository>你想存放的本地仓库路径< /localRepository>我这里用的阿里的中央仓库,也可以用网易的,或者Apache的(用国内的会更快一点)(不修改默认${user.home}/.m2/repository这个路径)至此,远程仓库已经配置完成。添加进去之后保存退出。_maven配置本地仓库路径

2023基于微信小程序的房屋租赁管理系统(SSM+mysql)-JAVA.VUE毕业设计(论文+开题报告+运行)_微信小程序-房屋管理系统-程序员宅基地

文章浏览阅读982次。本系统后台采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式,是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。图4-1系统工作原理图。_微信小程序-房屋管理系统

Java串口通讯基础概念-程序员宅基地

文章浏览阅读83次。串行通讯协议有很多种,像RS232,RS485,RS422,甚至现今流行的USB等都是串行通讯协议。而串行通讯技术的应用无处不在。可能大家见的最多就是电脑的串口与Modem的通讯。记得在PC机刚开始在中国流行起来时(大约是在90年代前五年),那时甚至有人用一条串行线进行两台电脑之间的数据共享。除了这些,手机,PDA,USB鼠标、键盘等等都是以串行通讯的方式与电脑连接。而笔者工作性质的关系,..._peak 串口

MySql索引失效及解决方案_mysql or索引失效如何解决-程序员宅基地

文章浏览阅读1.2k次。MySql索引失效及解决方案_mysql or索引失效如何解决

Android安卓实战项目(12)—关于身体分析,BMI计算,喝水提醒,食物卡路里计算APP【支持中英文切换】生活助手类APP(源码在文末)-程序员宅基地

文章浏览阅读1.1k次。Android安卓实战项目(12)---关于身体分析,BMI计算,喝水提醒,食物卡路里计算APP【支持中英文切换】生活助手类APP(源码在文末)

对于人工智能的理解_你对人工智能目的的理解-程序员宅基地

文章浏览阅读2.7k次。分享一下这几天对人工智能的想法人工智能,缩写AI。谈到人工智能,我们首先想到的,它是一门学科,要我们去学习,但人工智能的终极目标是对人的意识、思维过程的模拟,它能像人那样思考,甚至超过人的智能。人工智能是一个交叉学科,涉及多领域,多专业,所以其复杂度可想而知。虽然,现在的人工智能还处于初级阶段,但是,不缺我们对之想象探索。它将是现在以及未来社会建设和发展的主流之一,将会影响我们未来生活各个方面发生重大改变。当然,我们现在的生活中在很多运用人工智能,如很多网站的AI客服,网上购平台为了提前预见客户的需求_你对人工智能目的的理解

随便推点

html中的分离式布局,DIV+CSS技术在网页布局中的应用-程序员宅基地

文章浏览阅读814次。摘 要 信息科学技术的进步使得互联网技术行业快速发展起来。其中网页设计作为互联网技术行业中重要的一部分,应用先进技术提高其工作效率与工作质量具有重要意义。DIV+CSS技术在网页布局中的优势作用使得其在网页设计与开发中应用越来越广泛。基于此,本文首先对DIV+CSS技术进行概述,并对其在网页布局中的优势与应用原理进行分析,最后举出网页设计的实例对该项技术的具体应用进行分布阐述。【关键词】DIV C..._布局与样式分离

Spring源码分析——Bean的加载_在spring中bean的创建过程-程序员宅基地

文章浏览阅读240次。Spring版本:5.1.14.RELEASEBean实例创建过程如下图,Bean的创建过程大部分是在docreateBean()里面完成的。_在spring中bean的创建过程

RTT Studio和Cubemx联合开发_rtt cube-程序员宅基地

文章浏览阅读892次。1. RTT studio创建工程创建工程## 创建完成以后的目录结构2. 配置CubuMx双击cubumx的图标打开CubeMx配置时钟生成代码构建后的代码结构编译代码满屏错误:不要慌3. 新增脚本新建scons脚本文件 SConscript脚本内容如下import osfrom building import *cwd = GetCurrentDir()src = Glob('*.c')# add cubemx driverssrc = Split('''_rtt cube

java string 去掉某个字符_JAVA String 如何去掉指定字符-程序员宅基地

文章浏览阅读3.2w次,点赞4次,收藏10次。展开全部i、replace方法该方法的作用是替换字符串中所有指定的字e69da5e6ba9062616964757a686964616f31333337616637符,然后生成一个新的字符串。经过该方法调用以后,原来的字符串不发生改变。例如:Strings=“abcat”;Strings1=s.replace(‘a’,‘1’);该代码的作用是将字符串s中所有的字符a替换成字符1,生成的..._string去掉指定字符

java:手动实现一个IOC_java手写ioc-程序员宅基地

文章浏览阅读749次,点赞3次,收藏11次。面试官特别爱问SpringIOC底层实现,Spring源码晦涩难懂 怎么办呢? 跟着老师手动实现一个mini ioc容器吧,实现后再回头看Spring源码事半功倍哦~,就算直接和面试官讲也完全可以哦,类名完全按照源码设计,话不多说 开干~!手动实现IOC容器的设计需要实现的IOC功能:可以通过xml配置bean信息 可以通过容器getBean获取对象 能够根据Bean的依赖属性实现依赖注入 可以配置Bean的单例多例实现简易IOC设计的类类之间关系模型..._java手写ioc

【计算机网络】应用层详解_应用层解析-程序员宅基地

文章浏览阅读558次。1.协议1.1 应用层自定制协议HTTP协议1.2 传输层UDP协议TCP协议1.3 自定制协议自定制协议是应用层协议,被程序员定义出来的协议(应用层对要传输的数据,进行数据格式的约定,消息发送方和接收方都必须遵守约定)TCP特性:面向字节流 2.TCP粘包问题 我们需要在应用层自定制协议,自定制协议增加报头和分隔符【定长报头(数据长度)】+数据【定长报头】+ 数据+分隔符【不定长报头】+数据+分隔符 对于定长报头,双方的收发都是遵守约定的 不定长的_应用层解析

推荐文章

热门文章

相关标签