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

概述

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

温度曲线图

光强曲线图

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

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

这里要注意一下,最开始我通过strstr方法来找出关键字“hue”,但是测了下不行,后来找到原因,估计是平台下发的josn数据包中含有多个0,比方说设备收到的是“123456789”,这里的‘’其实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!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部分

#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部分

#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 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部分

#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服务器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部