上一篇使用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