我是靠谱客的博主 醉熏老鼠,这篇文章主要介绍【单片机笔记】STM32+ESP8266通过AT指令WIFI连接阿里云MQTT服务器,现在分享给大家,希望可以做个参考。

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

温度曲线图

光强曲线图

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

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

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

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

main.c部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#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!rn"); // Usart2_SendString(" usart2 is ok!rn"); 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!rn"); sta++; } else{ Oled_ShowString(0,0*16,"Net Init Error!",8,16,1); // printf("Net Init Error!rn"); 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!rn"); sta++; } else { Oled_ShowString(0,1*16,"Conncet AP Error!",8,16,1); // printf("Conncet AP Error!rn"); 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!rn"); sta++; } else{ Oled_ShowString(0,2*16,"Server Error!",8,16,1); // printf("Conncet Server Error!rn"); 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!rn"); sta++; } else{ Oled_ShowString(0,3*16,"Enter MQTT Error",8,16,1); // printf("Enter MQTT Error!rn"); 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!rn"); } else{ Oled_ShowString(0,0*16,"Subscribe Error!",8,16,1); // printf("SubscribeTopic Error!rn"); } 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 rn",temp); // Usart1_SendBuf(buf,len); } } /*********************************************END OF FILE********************************************/

net.c部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#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+RSTrn"); //重启ESP8266 Delay_ms(800); if(_net.Check()==0) //使用AT指令检查ESP8266是否存在 { return 0; } memset(_net.rxbuf,0,_net.rxlen); //清空接收缓冲 _net.SendString("ATE0rn"); //关闭回显 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+RESTORErn");//恢复出厂 // 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("ATrn"); //发送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=1rn"); //设置为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"rn",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",%drn",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+CIPSENDrn");//开始处于透传发送状态 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+CIPCLOSErn");//关闭链接 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=1rn"); 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部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#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 00 const 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部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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

 

最后

以上就是醉熏老鼠最近收集整理的关于【单片机笔记】STM32+ESP8266通过AT指令WIFI连接阿里云MQTT服务器的全部内容,更多相关【单片机笔记】STM32+ESP8266通过AT指令WIFI连接阿里云MQTT服务器内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部