STM32系列(HAL库)——使用ESP8266-01S物联网模块连接Onenet云平台上报DHT11温湿度

2023-05-16

前言

本篇主要讲解如何使用ESP8266-01S物联网模块连接Onenet云平台,并上报DHT11模块的温湿度数据。本文单片机主控采用STM32F405RGT6,使用其他主控的话基本要求有2个串口,一个串口用于调试使用,另一个用于ESP模块通讯。
在这里插入图片描述

一、前期准备

1.软件

  • CubeMX
  • Keil5
  • 串口调试助手
  • Onenet云平台账户

2.硬件

  • STM32开发板
  • 一个捡来的ESP8266-01S模块
  • 一个盗版的ST-link模块
  • 一个借的USB-TTL模块
  • 一个买的DHT11温湿度模块
  • 杜邦线若干

二、CubeMX配置

1.配置时钟源、下载模块、时钟树

2.引脚配置

这里配置了2个引脚,一个是LED,一个是DHT11
在这里插入图片描述

3.配置串口

串口使用2个,波特率默认115200即可,一个是串口1(PA9、PA10)用于调试使用,另外一个使用串口2(PA2、PA3)用于和ESP通讯,并注意打开串口2的接收中断,如下:
在这里插入图片描述

4.生成工程

三、Keil5配置

1.基本配置

①在根目录下创建一个文件夹用于保存后面的代码文件

在这里插入图片描述

②添加头文件路径

在这里插入图片描述

③在工程栏创建文件夹

在这里插入图片描述

2.配置串口代码

①这里参考以往文章,使用第三种方法:STM32系列(HAL库) ——使用串口打印的3种方式
②参考上述配置完后,还需要添加一个函数用于和EPS模块通讯,在usart.c添加:
void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len)
{

	unsigned short count = 0;
	
	for(; count < len; count++)
	{
		HAL_UART_Transmit (&USARTx ,(uint8_t *)str++,1,HAL_MAX_DELAY );									//发送数据
	}

}
③在usart.h声明函数:
void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len);
④验证UsartPrintf函数能成功打印内容,可在while(1)循环添加:
UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");
HAL_Delay(500);

效果如下:
在这里插入图片描述

3.配置DHT11代码

创建DHT11.c文件,添加代码如下:
#include "dht11.h"
#include "usart.h"
extern UART_HandleTypeDef huart1;
uint8_t data[5] = {0};
/**
  * @brief  温湿度传感器主函数
  * @param  void
  * @retval None
  */
void DHT11(void)
{
    if(DHT11_READ_DATA() == 1)
    {
//        printf("数据校验成功!\r\n");
        UsartPrintf(USART_DEBUG, "数据校验成功!\r\n");
    }
    else
    {
//        printf("DHT11没有应答,请检查传感器!\r\n");
        UsartPrintf(USART_DEBUG, "DHT11没有应答,请检查传感器!\r\n");
    }
    HAL_Delay(1000);                              
  
}
 
/**
  * @brief  温湿度传感器启动信号发送
  * @param  void
  * @retval None
  */
void DHT11_START(void)
{
    DHT11_GPIO_MODE_SET(0);                         //  主机设置为输出模式
    
    DHT11_PIN_RESET;                                //  主机拉低电平
    
    HAL_Delay(20);                                  //  主机等待 18 < ms > 30
    
    DHT11_GPIO_MODE_SET(1);                         //  主机设置为输入模式,等待DHT11答应
}                                                   //  因为设置了上拉输入,GPIO -> 1
 
/**
  * @brief  读取一位数据 1bit
  * @param  void
  * @retval 0/1
  */
unsigned char DHT11_READ_BIT(void)
{
    while(!DHT11_READ_IO);                          //  过度数据的低电平 
    
    Coarse_delay_us(40);
 
    if(DHT11_READ_IO)                               //  此时如果还为高电平则数据为 1
    {
        while(DHT11_READ_IO);                       //  过度数据的高电平
        return 1;
    }   
    else                                            //  若此时为低则为 0
    {
        return 0;
    }
}
 
/**
  * @brief  读取一个字节数据 1byte / 8bit
  * @param  void
  * @retval temp
  */
unsigned char DHT11_READ_BYTE(void)
{
    uint8_t i,temp = 0;                             //  暂时存储数据
    
    for(i=0; i<8 ;i++)
    {
        temp <<= 1;                                 
        if(DHT11_READ_BIT())                        //  1byte -> 8bit
        {
            temp |= 1;                              //  0000 0001
        }
    }
    return temp;
}
 
/**
  * @brief  读取温湿度传感器数据 5byte / 40bit
  * @param  void
  * @retval 0/1/2
  */
unsigned char DHT11_READ_DATA(void)
{
    uint8_t i;
   
    
    DHT11_START();                                  //  主机发送启动信号
    
    if(DHT11_Check())                               //  如果DHT11应答     
    {  
        while(!DHT11_READ_IO);                      //  过度DHT11答复信号的低电平
        while(DHT11_READ_IO);                       //  过度DHT11答复信号的高电平
        
        for(i=0; i<5; i++)
        {                        
            data[i] = DHT11_READ_BYTE();            //  读取 5byte
        }
        
        if(data[0] + data[1] + data[2] + data[3] == data[4])
        {
//            printf("当前湿度:%d.%d%%RH当前温度:%d.%d°C--",data[0],data[1],data[2],data[3]);
            UsartPrintf(USART_DEBUG,"当前湿度:%d.%d%%RH当前温度:%d.%d°C--",data[0],data[1],data[2],data[3]);
            return 1;                               //  数据校验通过
        }
        else
        {
            return 0;                               //  数据校验失败
        }
    }
    else                                            //  如果DHT11不应答
    {
        return 2;
    }
}
 
/**
  * @brief  检测温湿度传感器是否存在(检测DHT11的应答信号)
  * @param  void
  * @retval 0/1
  */
unsigned char DHT11_Check(void)
{
 
    Coarse_delay_us(40);
    if(DHT11_READ_IO == 0)                          //  检测到DHT11应答
    {
        return 1;
    }
    else                                            //  检测到DHT11不应答
    {
        return 0;
    }
}
 
/**
  * @brief  设置引脚模式
  * @param  mode: 0->out, 1->in
  * @retval None
  */
static void DHT11_GPIO_MODE_SET(uint8_t mode)
{
    if(mode)
    {
        /*  输入  */
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.Pin = GPIO_Pin;                   //  9号引脚
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;             //  输入模式
        GPIO_InitStruct.Pull = GPIO_PULLUP;                 //  上拉输入
        HAL_GPIO_Init(GPIO_Port, &GPIO_InitStruct);
    }
    else 
    {
        /*  输出  */
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.Pin = GPIO_Pin;                //  9号引脚
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;      //  Push Pull 推挽输出模式
        GPIO_InitStructure.Pull = GPIO_PULLUP;              //  上拉输出
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;    //  高速
        HAL_GPIO_Init(GPIO_Port,&GPIO_InitStructure);
    }
}
 
/**
  * @brief  程序延时 us 
  * @param  us: <= 4294967295
  * @retval None
  */
void Coarse_delay_us(uint32_t us)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
    while (delay--)
	{
		;
	}
}
 
②创建DHT11.h文件,添加代码如下:

注意修改引用的头文件#include “stm32f4xx.h”,我用的是F4系列的,F1系列为#include “stm32f1xx.h”,其它系列以此类推

#ifndef __DHT11_H__
#define __DHT11_H__
 
/* Private includes ----------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "stdio.h"
#include "stm32f4xx.h"
 
/* Private define ------------------------------------------------------------*/
#define GPIO_Port GPIOC
#define GPIO_Pin GPIO_PIN_4

#define DHT11_PIN_SET   HAL_GPIO_WritePin(GPIO_Port,GPIO_Pin,GPIO_PIN_SET)                                            //  设置GPIO为高
#define DHT11_PIN_RESET HAL_GPIO_WritePin(GPIO_Port,GPIO_Pin,GPIO_PIN_RESET)                                          //  设置GPIO为低
#define DHT11_READ_IO   HAL_GPIO_ReadPin(GPIO_Port,GPIO_Pin)                                                          //  DHT11 GPIO定义
 
extern uint8_t data[5];
 
/* Private function prototypes -----------------------------------------------*/
void DHT11(void);
void DHT11_START(void);
unsigned char DHT11_READ_BIT(void);
unsigned char DHT11_READ_BYTE(void);
unsigned char DHT11_READ_DATA(void);
unsigned char DHT11_Check(void);
static void DHT11_GPIO_MODE_SET(uint8_t mode);
 
void Coarse_delay_us(uint32_t us);
    
#endif
 
③验证DHT11模块

在工程栏处添加DHT11.c文件
在这里插入图片描述
在main.c引用DHT11.h头文件,while(1)循环添加:

DHT11(  );
HAL_Delay(1000);

效果如下:
在这里插入图片描述

4.ESP模块、通信协议代码配置

①创建esp01s.c文件,添加代码如下:

代码需要注意:

#define ESP01S_WIFI_INFO"AT+CWJAP=“OPPOA93”,“12345678”\r\n"

此语句定义了模块需要连接的网络,可以是wifi,可以是手机热点,前面是网络名称,如OPPOA93,后面是网络连接密码,如12345678


//单片机头文件
#include "main.h"

//网络设备驱动
#include "esp01s.h"

//硬件驱动
#include "usart.h"

//C库
#include <string.h>
#include <stdio.h>
#include <string.h>
 

#define ESP01S_WIFI_INFO		"AT+CWJAP=\"OPPOA93\",\"12345678\"\r\n"
#define ESP01S_ONENET_INFO		"AT+CIPSTART=\"TCP\",\"183.230.40.39\",6002\r\n"

unsigned char ESP01S_buf[128];
unsigned short ESP01S_cnt = 0, ESP01S_cntPre = 0;

uint8_t aRxBuffer;			//接收中断缓冲
//==========================================================
//	函数名称:	ESP01S_Clear
//
//	函数功能:	清空缓存
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP01S_Clear(void)
{

	memset(ESP01S_buf, 0, sizeof(ESP01S_buf));
	ESP01S_cnt = 0;

}

//==========================================================
//	函数名称:	ESP01S_WaitRecive
//
//	函数功能:	等待接收完成
//
//	入口参数:	无
//
//	返回参数:	REV_OK-接收完成		REV_WAIT-接收超时未完成
//
//	说明:		循环调用检测是否接收完成
//==========================================================
_Bool ESP01S_WaitRecive(void)
{

	if(ESP01S_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
		return REV_WAIT;
		
	if(ESP01S_cnt == ESP01S_cntPre)				//如果上一次的值和这次相同,则说明接收完毕
	{
		ESP01S_cnt = 0;							//清0接收计数
			
		return REV_OK;								//返回接收完成标志
	}
		
	ESP01S_cntPre = ESP01S_cnt;					//置为相同
	
	return REV_WAIT;								//返回接收未完成标志

}

//==========================================================
//	函数名称:	ESP01S_SendCmd
//
//	函数功能:	发送命令
//
//	入口参数:	cmd:命令
//				res:需要检查的返回指令
//
//	返回参数:	0-成功	1-失败
//
//	说明:		
//==========================================================
_Bool ESP01S_SendCmd(char *cmd, char *res)
{
	
	unsigned char timeOut = 200;

	Usart_SendString(huart2, (unsigned char *)cmd, strlen((const char *)cmd));
	
	while(timeOut--)
	{
		if(ESP01S_WaitRecive() == REV_OK)							//如果收到数据
		{
			if(strstr((const char *)ESP01S_buf, res) != NULL)		//如果检索到关键词
			{
				ESP01S_Clear();									//清空缓存
				
				return 0;
			}
		}
		
		HAL_Delay(10);
	}
	
	return 1;

}

//==========================================================
//	函数名称:	ESP01S_SendData
//
//	函数功能:	发送数据
//
//	入口参数:	data:数据
//				len:长度
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP01S_SendData(unsigned char *data, unsigned short len)
{

	char cmdBuf[32];
	
	ESP01S_Clear();								//清空接收缓存
	sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len);		//发送命令
	if(!ESP01S_SendCmd(cmdBuf, ">"))				//收到‘>’时可以发送数据
	{
		Usart_SendString(huart2, data, len);		//发送设备连接请求数据
	}

}

//==========================================================
//	函数名称:	ESP01S_GetIPD
//
//	函数功能:	获取平台返回的数据
//
//	入口参数:	等待的时间(乘以10ms)
//
//	返回参数:	平台返回的原始数据
//
//	说明:		不同网络设备返回的格式不同,需要去调试
//				如ESP01S的返回格式为	"+IPD,x:yyy"	x代表数据长度,yyy是数据内容
//==========================================================
unsigned char *ESP01S_GetIPD(unsigned short timeOut)
{

	char *ptrIPD = NULL;
	
	do
	{
		if(ESP01S_WaitRecive() == REV_OK)								//如果接收完成
		{
			ptrIPD = strstr((char *)ESP01S_buf, "IPD,");				//搜索“IPD”头
			if(ptrIPD == NULL)											//如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
			{
				//UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");
			}
			else
			{
				ptrIPD = strchr(ptrIPD, ':');							//找到':'
				if(ptrIPD != NULL)
				{
					ptrIPD++;
					return (unsigned char *)(ptrIPD);
				}
				else
					return NULL;
				
			}
		}
		
		HAL_Delay(5);
    timeOut--;		//延时等待
	} while(timeOut>0);
	
	return NULL;														//超时还未找到,返回空指针

}

//==========================================================
//	函数名称:	ESP01S_Init
//
//	函数功能:	初始化ESP01S
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP01S_Init(void)
{
	
	
	ESP01S_Clear();
	
	UsartPrintf(USART_DEBUG, "0. AT\r\n");
	while(ESP01S_SendCmd("AT\r\n", "OK"))
		HAL_Delay(500);
	
	UsartPrintf(USART_DEBUG, "1. RST\r\n");
	ESP01S_SendCmd("AT+RST\r\n", "");
        HAL_Delay(500);	
	
    ESP01S_SendCmd("AT+CIPCLOSE\r\n", "");              //关闭TCP连接
		HAL_Delay(500);	
	
	UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
	while(ESP01S_SendCmd("AT+CWMODE=1\r\n", "OK"))     //模式1(Station),默认保存Flash
		HAL_Delay(500);
	
	UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n");       //开启DHCP(获取分配IP),默认保存Flash
	while(ESP01S_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))  
		HAL_Delay(500);
	
	UsartPrintf(USART_DEBUG, "4. CWJAP\r\n");           //链接WIFI
	while(ESP01S_SendCmd(ESP01S_WIFI_INFO, "GOT IP"))
		HAL_Delay(500);
	
	UsartPrintf(USART_DEBUG, "5. CIPSTART\r\n");        //开启TCP连接
	while(ESP01S_SendCmd(ESP01S_ONENET_INFO, "CONNECT"))
		HAL_Delay(500);
	
	UsartPrintf(USART_DEBUG, "6. ESP01S Init OK\r\n"); 

}

/* USER CODE BEGIN 4 */
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  
    UNUSED(huart);
 
	if(ESP01S_cnt >= sizeof(ESP01S_buf))  //溢出判断
	{
		ESP01S_cnt = 0;
		memset(ESP01S_buf,0x00,sizeof(ESP01S_buf));
		HAL_UART_Transmit(&huart1, (uint8_t *)"接收缓存溢出", 10,0xFFFF); 	      
	}
	else
	{
		ESP01S_buf[ESP01S_cnt++] = aRxBuffer;   //接收数据转存	
//		  if(aRxBuffer=='1')  HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);
//        if(aRxBuffer=='0')  HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);
 	}
	
	HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断
}


/* USER CODE END 4 */

②创建esp01s.h文件,添加代码如下:
#ifndef _ESP01S_H_
#define _ESP01S_H_

#define REV_OK		0	//接收完成标志
#define REV_WAIT	1	//接收未完成标志

void ESP01S_Init(void);
void ESP01S_Clear(void);
void ESP01S_SendData(unsigned char *data, unsigned short len);
unsigned char *ESP01S_GetIPD(unsigned short timeOut);

#endif

③创建Onenet.c文件,添加代码如下:

这里需要注意代码中:
#define PROID “xxx” //产品ID
#define AUTH_INFO “xxx” //鉴权信息
#define DEVID “xxx” //设备ID
xxx的内容需要在Onenet云平台创建产品、设备后可得,后文会介绍



//单片机头文件
#include "main.h"

//网络设备
#include "esp01s.h"

//协议文件
#include "onenet.h"
#include "MQTT.h"

//硬件驱动
#include "usart.h"
//C库
#include <string.h>
#include <stdio.h>

#include "dht11.h"

#define PROID		"XXX"//产品ID

#define AUTH_INFO	"XXX"//鉴权信息

#define DEVID		"XXX"//设备ID


extern unsigned char ESP01S_buf[128];


//==========================================================
//	函数名称:	OneNet_DevLink
//
//	函数功能:	与onenet创建连接
//
//	入口参数:	无
//
//	返回参数:	1-成功	0-失败
//
//	说明:		与onenet平台建立连接
//==========================================================
_Bool OneNet_DevLink(void)
{
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};					//协议包

	unsigned char *dataPtr;
	
	_Bool status = 1;
	
	UsartPrintf(USART_DEBUG, "OneNet_DevLink\r\n"
							"PROID: %s,	AUIF: %s,	DEVID:%s\r\n"
                        , PROID, AUTH_INFO, DEVID);
	
	if(MQTT_PacketConnect(PROID, AUTH_INFO, DEVID, 256, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0)
	{
		ESP01S_SendData(mqttPacket._data, mqttPacket._len);			//上传平台
		
		dataPtr = ESP01S_GetIPD(250);									//等待平台响应
		if(dataPtr != NULL)
		{
			if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK)
			{
				switch(MQTT_UnPacketConnectAck(dataPtr))
				{
					case 0:UsartPrintf(USART_DEBUG, "Tips:	连接成功\r\n");status = 0;break;					
					case 1:UsartPrintf(USART_DEBUG, "WARN:	连接失败:协议错误\r\n");break;
					case 2:UsartPrintf(USART_DEBUG, "WARN:	连接失败:非法的clientid\r\n");break;
					case 3:UsartPrintf(USART_DEBUG, "WARN:	连接失败:服务器失败\r\n");break;
					case 4:UsartPrintf(USART_DEBUG, "WARN:	连接失败:用户名或密码错误\r\n");break;
					case 5:UsartPrintf(USART_DEBUG, "WARN:	连接失败:非法链接(比如token非法)\r\n");break;
					
					default:UsartPrintf(USART_DEBUG, "ERR:	连接失败:未知错误\r\n");break;
				}
			}
		}
		
		MQTT_DeleteBuffer(&mqttPacket);								//删包
	}
	else
		UsartPrintf(USART_DEBUG, "WARN:	MQTT_PacketConnect Failed\r\n");
	
	return status;
	
}

unsigned char OneNet_FillBuf(char *buf)
{
	
	char text[32];
	float Temp;
    float Humidity;
	memset(text, 0, sizeof(text));
	
	strcpy(buf, ",;");
	Temp = data[2]+(float)data[3]/10;
    Humidity=data[0]+(float)data[1]/10;
	memset(text, 0, sizeof(text));
	sprintf(text, "Temp,%.2f;Humidity,%.2f;",Temp,Humidity);
	strcat(buf, text);
	
	
	return strlen(buf);

}

//==========================================================
//	函数名称:	OneNet_SendData
//
//	函数功能:	上传数据到平台
//
//	入口参数:	type:发送数据的格式
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void OneNet_SendData(void)
{
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};												//协议包
	
	char buf[128];
	
	short body_len = 0, i = 0;
	
	UsartPrintf(USART_DEBUG, "Tips:	OneNet_SendData-MQTT\r\n");
	
	memset(buf, 0, sizeof(buf));
	
	body_len = OneNet_FillBuf(buf);																	//获取当前需要发送的数据流的总长度
	
	if(body_len)
	{
		if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0)							//封包
		{
			for(; i < body_len; i++)
				mqttPacket._data[mqttPacket._len++] = buf[i];
			
			ESP01S_SendData(mqttPacket._data, mqttPacket._len);									//上传数据到平台
			UsartPrintf(USART_DEBUG, "Send %d Bytes\r\n", mqttPacket._len);
			
			MQTT_DeleteBuffer(&mqttPacket);															//删包
		}
		else
			UsartPrintf(USART_DEBUG, "WARN:	EDP_NewBuffer Failed\r\n");
	}
	
}

//==========================================================
//	函数名称:	OneNet_RevPro
//
//	函数功能:	平台返回数据检测
//
//	入口参数:	dataPtr:平台返回的数据
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void OneNet_RevPro(unsigned char *cmd)
{
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};								//协议包
	
	char *req_payload = NULL;
	char *cmdid_topic = NULL;
	
	unsigned short req_len = 0;
	
	unsigned char type = 0;
	
	short result = 0;

	char *dataPtr = NULL;
	char numBuf[10];
	int num = 0;
	
	type = MQTT_UnPacketRecv(cmd);
	switch(type)
	{
		case MQTT_PKT_CMD:															//命令下发
			
			result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len);	//解出topic和消息体
			if(result == 0)
			{
				UsartPrintf(USART_DEBUG, "cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);
				
				if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0)	//命令回复组包
				{
					UsartPrintf(USART_DEBUG, "Tips:	Send CmdResp\r\n");
					
					ESP01S_SendData(mqttPacket._data, mqttPacket._len);			//回复命令
					MQTT_DeleteBuffer(&mqttPacket);									//删包
				}
			}
		
		break;
			
		case MQTT_PKT_PUBACK:														//发送Publish消息,平台回复的Ack
		
			if(MQTT_UnPacketPublishAck(cmd) == 0)
				UsartPrintf(USART_DEBUG, "Tips:	MQTT Publish Send OK\r\n");
			
		break;
		
		default:
			result = -1;
		break;
	}
	
	ESP01S_Clear();									//清空缓存
	
	if(result == -1)
		return;
	
	dataPtr = strchr(req_payload, '}');					//搜索'}'

	if(dataPtr != NULL && result != -1)					//如果找到了
	{
		dataPtr++;
		
		while(*dataPtr >= '0' && *dataPtr <= '9')		//判断是否是下发的命令控制数据
		{
			numBuf[num++] = *dataPtr++;
		}
		numBuf[num] = 0;
		
		num = atoi((const char *)numBuf);				//转为数值形式
	}

	if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH)
	{
		MQTT_FreeBuffer(cmdid_topic);
		MQTT_FreeBuffer(req_payload);
	}

}


④创建Onenet.h文件,添加代码如下:
#ifndef _ONENET_H_
#define _ONENET_H_

_Bool OneNet_DevLink(void);
void OneNet_SendData(void);
void OneNet_RevPro(unsigned char *cmd);

#endif

⑤创建MQTT.c文件,添加代码如下:


//协议头文件
#include "MQTT.h"

//C库
#include <string.h>
#include <stdio.h>


#define CMD_TOPIC_PREFIX		"$creq"


//==========================================================
//	函数名称:	EDP_NewBuffer
//
//	函数功能:	申请内存
//
//	入口参数:	edpPacket:包结构体
//				size:大小
//
//	返回参数:	无
//
//	说明:		1.可使用动态分配来分配内存
//				2.可使用局部或全局数组来指定内存
//==========================================================
void MQTT_NewBuffer(MQTT_PACKET_STRUCTURE *mqttPacket, uint32 size)
{
	
	uint32 i = 0;

	if(mqttPacket->_data == NULL)
	{
		mqttPacket->_memFlag = MEM_FLAG_ALLOC;
		
		mqttPacket->_data = (uint8 *)MQTT_MallocBuffer(size);
		if(mqttPacket->_data != NULL)
		{
			mqttPacket->_len = 0;
			
			mqttPacket->_size = size;
			
			for(; i < mqttPacket->_size; i++)
				mqttPacket->_data[i] = 0;
		}
	}
	else
	{
		mqttPacket->_memFlag = MEM_FLAG_STATIC;
		
		for(; i < mqttPacket->_size; i++)
			mqttPacket->_data[i] = 0;
		
		mqttPacket->_len = 0;
		
		if(mqttPacket->_size < size)
			mqttPacket->_data = NULL;
	}

}

//==========================================================
//	函数名称:	MQTT_DeleteBuffer
//
//	函数功能:	释放数据内存
//
//	入口参数:	edpPacket:包结构体
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	if(mqttPacket->_memFlag == MEM_FLAG_ALLOC)
		MQTT_FreeBuffer(mqttPacket->_data);
	
	mqttPacket->_data = NULL;
	mqttPacket->_len = 0;
	mqttPacket->_size = 0;
	mqttPacket->_memFlag = MEM_FLAG_NULL;

}

int32 MQTT_DumpLength(size_t len, uint8 *buf)
{
	
	int32 i = 0;
	
	for(i = 1; i <= 4; ++i)
	{
		*buf = len % 128;
		len >>= 7;
		if(len > 0)
		{
			*buf |= 128;
			++buf;
		}
		else
		{
			return i;
		}
	}

	return -1;
}

int32 MQTT_ReadLength(const uint8 *stream, int32 size, uint32 *len)
{
	
	int32 i;
	const uint8 *in = stream;
	uint32 multiplier = 1;

	*len = 0;
	for(i = 0; i < size; ++i)
	{
		*len += (in[i] & 0x7f) * multiplier;

		if(!(in[i] & 0x80))
		{
			return i + 1;
		}

		multiplier <<= 7;
		if(multiplier >= 2097152)		//128 * *128 * *128
		{
			return -2;					// error, out of range
		}
	}

	return -1;							// not complete

}

//==========================================================
//	函数名称:	MQTT_UnPacketRecv
//
//	函数功能:	MQTT数据接收类型判断
//
//	入口参数:	dataPtr:接收的数据指针
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketRecv(uint8 *dataPtr)
{
	
	uint8 status = 255;
	uint8 type = dataPtr[0] >> 4;				//类型检查
	
	if(type < 1 || type > 14)
		return status;
	
	if(type == MQTT_PKT_PUBLISH)
	{
		uint8 *msgPtr;
		uint32 remain_len = 0;
		
		msgPtr = dataPtr + MQTT_ReadLength(dataPtr + 1, 4, &remain_len) + 1;
		
		if(remain_len < 2 || dataPtr[0] & 0x01)					//retain
			return 255;
		
		if(remain_len < ((uint16)msgPtr[0] << 8 | msgPtr[1]) + 2)
			return 255;
		
		if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL)	//如果是命令下发
			status = MQTT_PKT_CMD;
		else
			status = MQTT_PKT_PUBLISH;
	}
	else
		status = type;
	
	return status;

}

//==========================================================
//	函数名称:	MQTT_PacketConnect
//
//	函数功能:	连接消息组包
//
//	入口参数:	user:用户名:产品ID
//				password:密码:鉴权信息或apikey
//				devid:设备ID
//				cTime:连接保持时间
//				clean_session:离线消息清除标志
//				qos:重发标志
//				will_topic:异常离线topic
//				will_msg:异常离线消息
//				will_retain:消息推送标志
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid,
						uint16 cTime, uint1 clean_session, uint1 qos,
						const int8 *will_topic, const int8 *will_msg, int32 will_retain,
						MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint8 flags = 0;
	uint8 will_topic_len = 0;
	uint16 total_len = 15;
	int16 len = 0, devid_len = strlen(devid);
	
	if(!devid)
		return 1;
	
	total_len += devid_len + 2;
	
	//断线后,是否清理离线消息:1-清理	0-不清理--------------------------------------------
	if(clean_session)
	{
		flags |= MQTT_CONNECT_CLEAN_SESSION;
	}
	
	//异常掉线情况下,服务器发布的topic------------------------------------------------------
	if(will_topic)
	{
		flags |= MQTT_CONNECT_WILL_FLAG;
		will_topic_len = strlen(will_topic);
		total_len += 4 + will_topic_len + strlen(will_msg);
	}
	
	//qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数-----------------------------
	switch((unsigned char)qos)
	{
		case MQTT_QOS_LEVEL0:
			flags |= MQTT_CONNECT_WILL_QOS0;							//最多一次
		break;
		
		case MQTT_QOS_LEVEL1:
			flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS1);	//最少一次
		break;
		
		case MQTT_QOS_LEVEL2:
			flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS2);	//只有一次
		break;
		
		default:
		return 2;
	}
	
	//主要用于PUBLISH(发布态)的消息,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它。如果不设那么推送至当前订阅的就释放了
	if(will_retain)
	{
		flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_RETAIN);
	}
	
	//账号为空 密码为空---------------------------------------------------------------------
	if(!user || !password)
	{
		return 3;
	}
	flags |= MQTT_CONNECT_USER_NAME | MQTT_CONNECT_PASSORD;
	
	total_len += strlen(user) + strlen(password) + 4;
	
	//分配内存-----------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, total_len);
	if(mqttPacket->_data == NULL)
		return 4;
	
	memset(mqttPacket->_data, 0, total_len);
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------连接请求类型---------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_CONNECT << 4;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(total_len - 5, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 5;
	}
	else
		mqttPacket->_len += len;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------协议名长度 和 协议名--------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	mqttPacket->_data[mqttPacket->_len++] = 4;
	mqttPacket->_data[mqttPacket->_len++] = 'M';
	mqttPacket->_data[mqttPacket->_len++] = 'Q';
	mqttPacket->_data[mqttPacket->_len++] = 'T';
	mqttPacket->_data[mqttPacket->_len++] = 'T';
	
	//可变头部----------------------protocol level 4-----------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 4;
	
	//可变头部----------------------连接标志(该函数开头处理的数据)-----------------------------
    mqttPacket->_data[mqttPacket->_len++] = flags;
	
	//可变头部----------------------保持连接的时间(秒)----------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(cTime);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(cTime);
	 
/*************************************消息体************************************************/

	//消息体----------------------------devid长度、devid-------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(devid_len);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(devid_len);
	
	strncat((int8 *)mqttPacket->_data + mqttPacket->_len, devid, devid_len);
	mqttPacket->_len += devid_len;
	
	//消息体----------------------------will_flag 和 will_msg---------------------------------
	if(flags & MQTT_CONNECT_WILL_FLAG)
	{
		unsigned short mLen = 0;
		
		if(!will_msg)
			will_msg = "";
		
		mLen = strlen(will_topic);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_topic, mLen);
		mqttPacket->_len += mLen;
		
		mLen = strlen(will_msg);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_msg, mLen);
		mqttPacket->_len += mLen;
	}
	
	//消息体----------------------------use---------------------------------------------------
	if(flags & MQTT_CONNECT_USER_NAME)
	{
		unsigned short user_len = strlen(user);
		
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(user_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(user_len);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, user, user_len);
		mqttPacket->_len += user_len;
	}

	//消息体----------------------------password----------------------------------------------
	if(flags & MQTT_CONNECT_PASSORD)
	{
		unsigned short psw_len = strlen(password);
		
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(psw_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(psw_len);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, password, psw_len);
		mqttPacket->_len += psw_len;
	}

	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketDisConnect
//
//	函数功能:	断开连接消息组包
//
//	入口参数:	mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketDisConnect(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 2);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_DISCONNECT << 4;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketConnectAck
//
//	函数功能:	连接消息解包
//
//	入口参数:	rev_data:接收的数据
//
//	返回参数:	1、255-失败		其他-平台的返回码
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketConnectAck(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;
	
	if(rev_data[2] == 0 || rev_data[2] == 1)
		return rev_data[3];
	else
		return 255;

}

//==========================================================
//	函数名称:	MQTT_PacketSaveData
//
//	函数功能:	数据点上传组包
//
//	入口参数:	devid:设备ID(可为空)
//				send_buf:json缓存buf
//				send_len:json总长
//				type_bin_head:bin文件的消息头
//				type:类型
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketSaveData(const int8 *devid, int16 send_len, int8 *type_bin_head, uint8 type, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, "$dp", NULL, send_len + 3, MQTT_QOS_LEVEL1, 0, 1, mqttPacket) == 0)
	{
		mqttPacket->_data[mqttPacket->_len++] = type;					//类型
		
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(send_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(send_len);
	}
	else
		return 1;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketSaveBinData
//
//	函数功能:	为禁止文件上传组包
//
//	入口参数:	name:数据流名字
//				file_len:文件长度
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketSaveBinData(const int8 *name, int16 file_len, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	uint1 result = 1;
	int8 *bin_head = NULL;
	uint8 bin_head_len = 0;
	int8 *payload = NULL;
	int32 payload_size = 0;
	
	bin_head = (int8 *)MQTT_MallocBuffer(13 + strlen(name));
	if(bin_head == NULL)
		return result;
	
	sprintf(bin_head, "{\"ds_id\":\"%s\"}", name);
	
	bin_head_len = strlen(bin_head);
	payload_size = 7 + bin_head_len + file_len;
	
	payload = (int8 *)MQTT_MallocBuffer(payload_size - file_len);
	if(payload == NULL)
	{
		MQTT_FreeBuffer(bin_head);
		
		return result;
	}
	
	payload[0] = 2;						//类型
		
	payload[1] = MOSQ_MSB(bin_head_len);
	payload[2] = MOSQ_LSB(bin_head_len);
	
	memcpy(payload + 3, bin_head, bin_head_len);
	
	payload[bin_head_len + 3] = (file_len >> 24) & 0xFF;
	payload[bin_head_len + 4] = (file_len >> 16) & 0xFF;
	payload[bin_head_len + 5] = (file_len >> 8) & 0xFF;
	payload[bin_head_len + 6] = file_len & 0xFF;
	
	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, "$dp", payload, payload_size, MQTT_QOS_LEVEL1, 0, 1, mqttPacket) == 0)
		result = 0;
	
	MQTT_FreeBuffer(bin_head);
	MQTT_FreeBuffer(payload);
	
	return result;

}

//==========================================================
//	函数名称:	MQTT_UnPacketCmd
//
//	函数功能:	命令下发解包
//
//	入口参数:	rev_data:接收的数据指针
//				cmdid:cmdid-uuid
//				req:命令
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketCmd(uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len)
{

	int8 *dataPtr = strchr((int8 *)rev_data + 6, '/');	//加6是跳过头信息
	
	uint32 remain_len = 0;
	
	if(dataPtr == NULL)									//未找到'/'
		return 1;
	dataPtr++;											//跳过'/'
	
	MQTT_ReadLength(rev_data + 1, 4, &remain_len);		//读取剩余字节
	
	*cmdid = (int8 *)MQTT_MallocBuffer(37);				//cmdid固定36字节,多分配一个结束符的位置
	if(*cmdid == NULL)
		return 2;
	
	memset(*cmdid, 0, 37);								//全部清零
	memcpy(*cmdid, (const int8 *)dataPtr, 36);			//复制cmdid
	dataPtr += 36;
	
	*req_len = remain_len - 44;							//命令长度 = 剩余长度(remain_len) - 2 - 5($creq) - 1(\) - cmdid长度
	*req = (int8 *)MQTT_MallocBuffer(*req_len + 1);		//分配命令长度+1
	if(*req == NULL)
	{
		MQTT_FreeBuffer(*cmdid);
		return 3;
	}
	
	memset(*req, 0, *req_len + 1);						//清零
	memcpy(*req, (const int8 *)dataPtr, *req_len);		//复制命令
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketCmdResp
//
//	函数功能:	命令回复组包
//
//	入口参数:	cmdid:cmdid
//				req:命令
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketCmdResp(const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint16 cmdid_len = strlen(cmdid);
	uint16 req_len = strlen(req);
	_Bool status = 0;
	
	int8 *payload = MQTT_MallocBuffer(cmdid_len + 7);
	if(payload == NULL)
		return 1;
	
	memset(payload, 0, cmdid_len + 7);
	memcpy(payload, "$crsp/", 6);
	strncat(payload, cmdid, cmdid_len);

	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, payload, req, strlen(req), MQTT_QOS_LEVEL0, 0, 1, mqttPacket) == 0)
		status = 0;
	else
		status = 1;
	
	MQTT_FreeBuffer(payload);
	
	return status;

}

//==========================================================
//	函数名称:	MQTT_PacketSubscribe
//
//	函数功能:	Subscribe消息组包
//
//	入口参数:	pkt_id:pkt_id
//				qos:消息重发次数
//				topics:订阅的消息
//				topics_cnt:订阅的消息个数
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint32 topic_len = 0, remain_len = 0;
	int16 len = 0;
	uint8 i = 0;
	
	if(pkt_id == 0)
		return 1;
	
	//计算topic长度-------------------------------------------------------------------------
	for(; i < topics_cnt; i++)
	{
		if(topics[i] == NULL)
			return 2;
		
		topic_len += strlen(topics[i]);
	}
	
	//2 bytes packet id + topic filter(2 bytes topic + topic length + 1 byte reserve)------
	remain_len = 2 + 3 * topics_cnt + topic_len;
	
	//分配内存------------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, remain_len + 5);
	if(mqttPacket->_data == NULL)
		return 3;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_SUBSCRIBE << 4 | 0x02;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 4;
	}
	else
		mqttPacket->_len += len;
	
/*************************************payload***********************************************/
	
	//payload----------------------pkt_id---------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id);
	
	//payload----------------------topic_name-----------------------------------------------
	for(i = 0; i < topics_cnt; i++)
	{
		topic_len = strlen(topics[i]);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len);
		
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics[i], topic_len);
		mqttPacket->_len += topic_len;
		
		mqttPacket->_data[mqttPacket->_len++] = qos & 0xFF;
	}

	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketSubscrebe
//
//	函数功能:	Subscribe的回复消息解包
//
//	入口参数:	rev_data:接收到的信息
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketSubscribe(uint8 *rev_data)
{
	
	uint8 result = 255;

	if(rev_data[2] == MOSQ_MSB(MQTT_SUBSCRIBE_ID) && rev_data[3] == MOSQ_LSB(MQTT_SUBSCRIBE_ID))
	{
		switch(rev_data[4])
		{
			case 0x00:
			case 0x01:
			case 0x02:
				//MQTT Subscribe OK
				result = 0;
			break;
			
			case 0x80:
				//MQTT Subscribe Failed
				result = 1;
			break;
			
			default:
				//MQTT Subscribe UnKnown Err
				result = 2;
			break;
		}
	}
	
	return result;

}

//==========================================================
//	函数名称:	MQTT_PacketUnSubscribe
//
//	函数功能:	UnSubscribe消息组包
//
//	入口参数:	pkt_id:pkt_id
//				qos:消息重发次数
//				topics:订阅的消息
//				topics_cnt:订阅的消息个数
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketUnSubscribe(uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint32 topic_len = 0, remain_len = 0;
	int16 len = 0;
	uint8 i = 0;
	
	if(pkt_id == 0)
		return 1;
	
	//计算topic长度-------------------------------------------------------------------------
	for(; i < topics_cnt; i++)
	{
		if(topics[i] == NULL)
			return 2;
		
		topic_len += strlen(topics[i]);
	}
	
	//2 bytes packet id, 2 bytes topic length + topic + 1 byte reserve---------------------
	remain_len = 2 + (topics_cnt << 1) + topic_len;
	
	//分配内存------------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, remain_len + 5);
	if(mqttPacket->_data == NULL)
		return 3;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_UNSUBSCRIBE << 4 | 0x02;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 4;
	}
	else
		mqttPacket->_len += len;
	
/*************************************payload***********************************************/
	
	//payload----------------------pkt_id---------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id);
	
	//payload----------------------topic_name-----------------------------------------------
	for(i = 0; i < topics_cnt; i++)
	{
		topic_len = strlen(topics[i]);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len);
		
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics[i], topic_len);
		mqttPacket->_len += topic_len;
	}

	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketUnSubscribe
//
//	函数功能:	UnSubscribe的回复消息解包
//
//	入口参数:	rev_data:接收到的信息
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketUnSubscribe(uint8 *rev_data)
{
	
	uint1 result = 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_UNSUBSCRIBE_ID) && rev_data[3] == MOSQ_LSB(MQTT_UNSUBSCRIBE_ID))
	{
		result = 0;
	}
	
	return result;

}

//==========================================================
//	函数名称:	MQTT_PacketPublish
//
//	函数功能:	Pulish消息组包
//
//	入口参数:	pkt_id:pkt_id
//				topic:发布的topic
//				payload:消息体
//				payload_len:消息体长度
//				qos:重发次数
//				retain:离线消息推送
//				own:
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketPublish(uint16 pkt_id, const int8 *topic,
						const int8 *payload, uint32 payload_len,
						enum MqttQosLevel qos, int32 retain, int32 own,
						MQTT_PACKET_STRUCTURE *mqttPacket)
{

	uint32 total_len = 0, topic_len = 0;
	uint32 data_len = 0;
	int32 len = 0;
	uint8 flags = 0;
	
	//pkt_id检查----------------------------------------------------------------------------
	if(pkt_id == 0)
		return 1;
	
	//$dp为系统上传数据点的指令--------------------------------------------------------------
	for(topic_len = 0; topic[topic_len] != '\0'; ++topic_len)
	{
		if((topic[topic_len] == '#') || (topic[topic_len] == '+'))
			return 2;
	}
	
	//Publish消息---------------------------------------------------------------------------
	flags |= MQTT_PKT_PUBLISH << 4;
	
	//retain标志----------------------------------------------------------------------------
	if(retain)
		flags |= 0x01;
	
	//总长度--------------------------------------------------------------------------------
	total_len = topic_len + payload_len + 2;
	
	//qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数-----------------------------
	switch(qos)
	{
		case MQTT_QOS_LEVEL0:
			flags |= MQTT_CONNECT_WILL_QOS0;	//最多一次
		break;
		
		case MQTT_QOS_LEVEL1:
			flags |= 0x02;						//最少一次
			total_len += 2;
		break;
		
		case MQTT_QOS_LEVEL2:
			flags |= 0x04;						//只有一次
			total_len += 2;
		break;
		
		default:
		return 3;
	}
	
	//分配内存------------------------------------------------------------------------------
	if(payload != NULL)
	{
		if(payload[0] == 2)
		{
			uint32 data_len_t = 0;
			
			while(payload[data_len_t++] != '}');
			data_len_t -= 3;
			data_len = data_len_t + 7;
			data_len_t = payload_len - data_len;
			
			MQTT_NewBuffer(mqttPacket, total_len + 3 - data_len_t);
			
			if(mqttPacket->_data == NULL)
				return 4;
			
			memset(mqttPacket->_data, 0, total_len + 3 - data_len_t);
		}
		else
		{
			MQTT_NewBuffer(mqttPacket, total_len + 5);
			
			if(mqttPacket->_data == NULL)
				return 4;
			
			memset(mqttPacket->_data, 0, total_len + 5);
		}
	}
	else
	{
		MQTT_NewBuffer(mqttPacket, total_len + 5);
		
		if(mqttPacket->_data == NULL)
			return 4;
		
		memset(mqttPacket->_data, 0, total_len + 5);
	}
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = flags;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(total_len, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 5;
	}
	else
		mqttPacket->_len += len;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------写入topic长度、topic-------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len);
	
	strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topic, topic_len);
	mqttPacket->_len += topic_len;
	if(qos != MQTT_QOS_LEVEL0)
	{
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id);
	}
	
	//可变头部----------------------写入payload----------------------------------------------
	if(payload != NULL)
	{
		if(payload[0] == 2)
		{
			memcpy((int8 *)mqttPacket->_data + mqttPacket->_len, payload, data_len);
			mqttPacket->_len += data_len;
		}
		else
		{
			memcpy((int8 *)mqttPacket->_data + mqttPacket->_len, payload, payload_len);
			mqttPacket->_len += payload_len;
		}
	}
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublish
//
//	函数功能:	Publish消息解包
//
//	入口参数:	flags:MQTT相关标志信息
//				pkt:指向可变头部
//				size:固定头部中的剩余长度信息
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketPublish(uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id)
{
	
	const int8 flags = rev_data[0] & 0x0F;
	uint8 *msgPtr;
	uint32 remain_len = 0;

	const int8 dup = flags & 0x08;

	*qos = (flags & 0x06) >> 1;
	
	msgPtr = rev_data + MQTT_ReadLength(rev_data + 1, 4, &remain_len) + 1;
	
	if(remain_len < 2 || flags & 0x01)							//retain
		return 255;
	
	*topic_len = (uint16)msgPtr[0] << 8 | msgPtr[1];
	if(remain_len < *topic_len + 2)
		return 255;
	
	if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL)	//如果是命令下发
		return MQTT_PKT_CMD;
	
	switch(*qos)
	{
		case MQTT_QOS_LEVEL0:									// qos0 have no packet identifier
			
			if(0 != dup)
				return 255;

			*topic = MQTT_MallocBuffer(*topic_len + 1);			//为topic分配内存
			if(*topic == NULL)
				return 255;
			
			memset(*topic, 0, *topic_len + 1);
			memcpy(*topic, (int8 *)msgPtr + 2, *topic_len);		//复制数据
			
			*payload_len = remain_len - 2 - *topic_len;			//为payload分配内存
			*payload = MQTT_MallocBuffer(*payload_len + 1);
			if(*payload == NULL)								//如果失败
			{
				MQTT_FreeBuffer(*topic);						//则需要把topic的内存释放掉
				return 255;
			}
			
			memset(*payload, 0, *payload_len + 1);
			memcpy(*payload, (int8 *)msgPtr + 2 + *topic_len, *payload_len);
			
		break;

		case MQTT_QOS_LEVEL1:
		case MQTT_QOS_LEVEL2:
			
			if(*topic_len + 2 > remain_len)
				return 255;
			
			*pkt_id = (uint16)msgPtr[*topic_len + 2] << 8 | msgPtr[*topic_len + 3];
			if(pkt_id == 0)
				return 255;
			
			*topic = MQTT_MallocBuffer(*topic_len + 1);			//为topic分配内存
			if(*topic == NULL)
				return 255;
			
			memset(*topic, 0, *topic_len + 1);
			memcpy(*topic, (int8 *)msgPtr + 2, *topic_len);		//复制数据
			
			*payload_len = remain_len - 4 - *topic_len;
			*payload = MQTT_MallocBuffer(*payload_len + 1);		//为payload分配内存
			if(*payload == NULL)								//如果失败
			{
				MQTT_FreeBuffer(*topic);						//则需要把topic的内存释放掉
				return 255;
			}
			
			memset(*payload, 0, *payload_len + 1);
			memcpy(*payload, (int8 *)msgPtr + 4 + *topic_len, *payload_len);
			
		break;

		default:
			return 255;
	}
	
	if(strchr((int8 *)topic, '+') || strchr((int8 *)topic, '#'))
		return 255;

	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishAck
//
//	函数功能:	Publish Ack消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为1时,需要Ack回复
//==========================================================
uint1 MQTT_PacketPublishAck(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBACK << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishAck
//
//	函数功能:	Publish Ack消息解包
//
//	入口参数:	rev_data:收到的数据
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishAck(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishRec
//
//	函数功能:	Publish Rec消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为2时,先收到rec
//==========================================================
uint1 MQTT_PacketPublishRec(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREC << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishRec
//
//	函数功能:	Publish Rec消息解包
//
//	入口参数:	rev_data:接收到的数据
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishRec(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishRel
//
//	函数功能:	Publish Rel消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel
//==========================================================
uint1 MQTT_PacketPublishRel(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREL << 4 | 0x02;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishRel
//
//	函数功能:	Publish Rel消息解包
//
//	入口参数:	rev_data:接收到的数据
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishRel(uint8 *rev_data, uint16 pkt_id)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(pkt_id) && rev_data[3] == MOSQ_LSB(pkt_id))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishComp
//
//	函数功能:	Publish Comp消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel
//==========================================================
uint1 MQTT_PacketPublishComp(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBCOMP << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishComp
//
//	函数功能:	Publish Comp消息解包
//
//	入口参数:	rev_data:接收到的数据
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishComp(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPing
//
//	函数功能:	心跳请求组包
//
//	入口参数:	mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketPing(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 2);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PINGREQ << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	
	return 0;

}

⑥创建MQTT.h文件,添加代码如下:
#ifndef _MQTT_H_
#define _MQTT_H_

#include <stdlib.h>
//=============================配置==============================
//===========可以提供RTOS的内存管理方案,也可以使用C库的=========
//RTOS

	typedef _Bool			uint1;
    typedef unsigned char   uint8;
    typedef char			int8;
    typedef unsigned short  uint16;
    typedef short			int16;
    typedef unsigned int    uint32;
    typedef int				int32;
	typedef unsigned int	size_t;
	
#define MQTT_MallocBuffer	malloc

#define MQTT_FreeBuffer		free
//==========================================================


#define MOSQ_MSB(A)         (uint8)((A & 0xFF00) >> 8)
#define MOSQ_LSB(A)         (uint8)(A & 0x00FF)
/*--------------------------------内存分配方案标志--------------------------------*/
#define MEM_FLAG_NULL		0
#define MEM_FLAG_ALLOC		1
#define MEM_FLAG_STATIC		2

typedef struct Buffer
{
	
	uint8	*_data;		//协议数据
	
	uint32	_len;		//写入的数据长度
	
	uint32	_size;		//缓存总大小
	
	uint8	_memFlag;	//内存使用的方案:0-未分配	1-使用的动态分配		2-使用的固定内存
	
} MQTT_PACKET_STRUCTURE;
/*--------------------------------固定头部消息类型--------------------------------*/
enum MqttPacketType
{
	
    MQTT_PKT_CONNECT = 1, /**< 连接请求数据包 */
    MQTT_PKT_CONNACK,     /**< 连接确认数据包 */
    MQTT_PKT_PUBLISH,     /**< 发布数据数据包 */
    MQTT_PKT_PUBACK,      /**< 发布确认数据包 */
    MQTT_PKT_PUBREC,      /**< 发布数据已接收数据包,Qos 2时,回复MQTT_PKT_PUBLISH */
    MQTT_PKT_PUBREL,      /**< 发布数据释放数据包, Qos 2时,回复MQTT_PKT_PUBREC */
    MQTT_PKT_PUBCOMP,     /**< 发布完成数据包, Qos 2时,回复MQTT_PKT_PUBREL */
    MQTT_PKT_SUBSCRIBE,   /**< 订阅数据包 */
    MQTT_PKT_SUBACK,      /**< 订阅确认数据包 */
    MQTT_PKT_UNSUBSCRIBE, /**< 取消订阅数据包 */
    MQTT_PKT_UNSUBACK,    /**< 取消订阅确认数据包 */
    MQTT_PKT_PINGREQ,     /**< ping 数据包 */
    MQTT_PKT_PINGRESP,    /**< ping 响应数据包 */
    MQTT_PKT_DISCONNECT,  /**< 断开连接数据包 */
	
	//新增
	
	MQTT_PKT_CMD  		 /**< 命令下发数据包 */
	
};
/*--------------------------------MQTT QOS等级--------------------------------*/
enum MqttQosLevel
{
	
    MQTT_QOS_LEVEL0,  /**< 最多发送一次 */
    MQTT_QOS_LEVEL1,  /**< 最少发送一次  */
    MQTT_QOS_LEVEL2   /**< 只发送一次 */
	
};
/*--------------------------------MQTT 连接请求标志位,内部使用--------------------------------*/
enum MqttConnectFlag
{
	
    MQTT_CONNECT_CLEAN_SESSION  = 0x02,
    MQTT_CONNECT_WILL_FLAG      = 0x04,
    MQTT_CONNECT_WILL_QOS0      = 0x00,
    MQTT_CONNECT_WILL_QOS1      = 0x08,
    MQTT_CONNECT_WILL_QOS2      = 0x10,
    MQTT_CONNECT_WILL_RETAIN    = 0x20,
    MQTT_CONNECT_PASSORD        = 0x40,
    MQTT_CONNECT_USER_NAME      = 0x80
	
};
/*--------------------------------消息的packet ID,可自定义--------------------------------*/
#define MQTT_PUBLISH_ID			10

#define MQTT_SUBSCRIBE_ID		20

#define MQTT_UNSUBSCRIBE_ID		30


/*--------------------------------删包--------------------------------*/
void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------解包--------------------------------*/
uint8 MQTT_UnPacketRecv(uint8 *dataPtr);

/*--------------------------------登录组包--------------------------------*/
uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid,
						uint16 cTime, uint1 clean_session, uint1 qos,
						const int8 *will_topic, const int8 *will_msg, int32 will_retain,
						MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------断开连接组包--------------------------------*/
uint1 MQTT_PacketDisConnect(MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------连接响应解包--------------------------------*/
uint8 MQTT_UnPacketConnectAck(uint8 *rev_data);

/*--------------------------------数据点上传组包--------------------------------*/
uint1 MQTT_PacketSaveData(const int8 *devid, int16 send_len, int8 *type_bin_head, uint8 type, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------二进制文件上传组包--------------------------------*/
uint1 MQTT_PacketSaveBinData(const int8 *name, int16 file_len, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------命令下发解包--------------------------------*/
uint8 MQTT_UnPacketCmd(uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len);

/*--------------------------------命令回复组包--------------------------------*/
uint1 MQTT_PacketCmdResp(const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------订阅主题组包--------------------------------*/
uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------订阅主题回复解包--------------------------------*/
uint8 MQTT_UnPacketSubscribe(uint8 *rev_data);

/*--------------------------------取消订阅组包--------------------------------*/
uint8 MQTT_PacketUnSubscribe(uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------取消订阅回复解包--------------------------------*/
uint1 MQTT_UnPacketUnSubscribe(uint8 *rev_data);

/*--------------------------------发布主题组包--------------------------------*/
uint8 MQTT_PacketPublish(uint16 pkt_id, const int8 *topic,
						const int8 *payload, uint32 payload_len,
						enum MqttQosLevel qos, int32 retain, int32 own,
						MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息回复解包--------------------------------*/
uint8 MQTT_UnPacketPublish(uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id);

/*--------------------------------发布消息的Ack组包--------------------------------*/
uint1 MQTT_PacketPublishAck(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Ack解包--------------------------------*/
uint1 MQTT_UnPacketPublishAck(uint8 *rev_data);

/*--------------------------------发布消息的Rec组包--------------------------------*/
uint1 MQTT_PacketPublishRec(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Rec解包--------------------------------*/
uint1 MQTT_UnPacketPublishRec(uint8 *rev_data);

/*--------------------------------发布消息的Rel组包--------------------------------*/
uint1 MQTT_PacketPublishRel(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Rel解包--------------------------------*/
uint1 MQTT_UnPacketPublishRel(uint8 *rev_data, uint16 pkt_id);

/*--------------------------------发布消息的Comp组包--------------------------------*/
uint1 MQTT_PacketPublishComp(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Comp解包--------------------------------*/
uint1 MQTT_UnPacketPublishComp(uint8 *rev_data);

/*--------------------------------心跳请求组包--------------------------------*/
uint1 MQTT_PacketPing(MQTT_PACKET_STRUCTURE *mqttPacket);

#endif

⑦将上述文件添加进工程栏

编译工程,如有报错自行改正即可
在这里插入图片描述

四、Onenet云平台配置

①平台账号注册→点击跳转

②创建产品、设备(按图示操作即可)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

③记录产品ID、设备ID、鉴权信息

在这里插入图片描述

五、最后一步

1.在esp01.c中修改wifi信息

修改成自己家或邻居家的wifi,或者手机热点;如下所示OPPOA93为网络名称,12345678为网络连接密码

#define ESP01S_WIFI_INFO “AT+CWJAP=“OPPOA93”,“12345678”\r\n”

2.在Onenet.c修改配置信息

修改成刚才从云平台获取的信息即可
在这里插入图片描述

3.main.c

①.在main.c引用头文件、定义如下变量:
#include "DHT11.h"
#include "esp01s.h"
#include "Onenet.h"
#include "MQTT.h"
extern uint8_t aRxBuffer;	
unsigned short timeCount = 0;	//发送间隔变量
unsigned char *dataPtr = NULL;
②.在while(1)前添加一些初始化函数
    UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");
    HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); //串口2接收中断初始化
    ESP01S_Init();  //8266初始化
    while(OneNet_DevLink())  //接入onenet
    ESP01S_Clear();    //
    UsartPrintf(USART_DEBUG, "Init is OK!\r\n");
③.在while(1)循环中添加:
 if(++timeCount >= 80)									//上传数据约3s一次
		{
            DHT11(  );            
			UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");
	        OneNet_SendData( );			 
			timeCount = 0;
			ESP01S_Clear( );
		}
		
        
		  dataPtr = ESP01S_GetIPD(3);//完成需要15个毫秒,三次循环,一次5个毫秒       
		  if(dataPtr != NULL)
          {                         
	      OneNet_RevPro(dataPtr);
          }
		  HAL_Delay(10); 

4.代码验证

①.接线图

在这里插入图片描述

②.串口1打印的信息

在这里插入图片描述

③.串口2打印的信息

STM32给ESP发送的信息,一般情况下硬件不支持看不到,因为32引脚和EPS连接后,就没法和USB-TTL连接了。因为我自制的开发板,所以能同时收到两者的通信
在这里插入图片描述

5.平台数据查看

在这里插入图片描述
在这里插入图片描述

代码是从标准库移植过来的,调试整理总结花了一定时间,全文没有过多的理论知识介绍,因为网上一搜一大把。全文如有错误,还请读者指正!

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32系列(HAL库)——使用ESP8266-01S物联网模块连接Onenet云平台上报DHT11温湿度 的相关文章

  • 获取本机所有网卡的网卡名、网卡描述、网卡MAC地址、网卡IP、网卡类型等信息及网线是否插入状态

    使用windows sdk提供的API函数GetAdaptersInfo 可以获得本机所有网卡的网卡名 网卡描述 网卡MAC地址 网卡IP 网卡类型等信息 xff0c 并用IP ADAPTER INFO结构体存储 xff0c 使用GetIf
  • C++ GUI Programming with Qt4 Second Edition 之 附录C.1 Qt Jambi入门

    Qt Jambi入门 本节 xff0c 我们将开发一个简单的Java应用程序并显示如图C 1所示的窗口 除窗口标题之外 xff0c Jambi Find对话框与第二章中创建的Find对话框的外观和功能均相同 通过使用相同的例子 xff0c
  • WinRAR 5.5 简体中文版去广告弹窗方法

    WinRAR 5 5 简体中文版去广告弹窗方法 1 下载WinRAR 5 5WinRAR官网 xff08 http www rarlab com xff09 2 下载 Resource Hacker 3 用压缩软件打开WinRAR安装包 x
  • C++子类的构造函数后面加:冒号的作用

    在C 43 43 类的构造函数中经常会看到如下格式的写法 xff1a MyWindow MyWindow QWidget parent Qt WindowFlags flag QMainWindow parent flag 上述语句中单冒号
  • “真相”重要吗?

    这是一篇个人思索的鸡汤 xff0c 并不想表达什么观点 xff0c 只是因为有了要写的冲动才写的 言归正传 xff0c 我认为 真相很重要 周末回老家看了一岁半儿子 xff0c 从国庆送回老家已经一个半月了 周日下午我临走时 xff0c 他
  • TDD(测试驱动开发)

    今天看到的新的有意思的名词 xff0c 在此将其记录下来 一 TDD是什么 xff1f Test Drive Development xff0c 是敏捷开发中的一项核心实践和技术 也是一种设计方法论 xff0c 其基本思想就是 xff1a
  • c++ 常见的一些问题总结

    目录 目录 1 深拷贝 xff08 string xff09 深拷贝的实现 xff08 xff09 2 迭代器失效 xff08 vector insert xff0c earse xff09 3 头文件展开问题 4 vector 的深浅拷贝
  • airflow 文档学习(二) - 概念

    1 核心功能 1 1 DAGs 有向无环图 反映所涉及的task的依赖关系 注 xff1a 搜索dag的时候 xff0c airflow只会关注同事包含 34 DAG 34 和 34 airflow 34 字样的py文件 1 2 scope
  • 2014创新工场校园招聘笔试题(9.16北京)

    选择题 1 若进栈序列为a b c d xff0c 进栈过程中可以出栈 xff0c 那么 xff08 xff09 不可能是一个出栈序列 A cbad B bdca C adbc D cdba 2 完全二叉树中编号为i的结点存在右孩子 xff
  • 2014美团校园招聘笔试(10.8北京)

    按照试卷要求不能透露题目具体内容 xff0c 因此本文只写考点 一共六道大题 xff0c 如下 xff1a Q1 基础题 xff0c 给出中序后序 xff0c 求前序 Q2 概率题 xff0c 求期望 Q3 概率题 xff0c 求可能性 Q
  • 2014去哪儿网校园招聘笔试(10.13北京)

    三道大题 43 两题TestCase 编程题 Q1 xff1a 实现一个字符串反转 xff0c 规则如下 xff1a 输入一个字符串str xff0c 一个分隔符delim xff0c 要求实现对分隔符之间的字符串做反转操作 xff0c 但
  • 图像处理算法工程师职位面试题汇总

    最近面试了几个图像的职位 xff0c 汇总一下面试题 图像基础知识 xff1a 1 常用的图像空间 2 简述你熟悉的聚类算法并说明其优缺点 3 请描述以下任一概念 xff1a SIFT SURF LDA PCA 4 请说出使用过的分类器和实
  • 软件开发职位面试题汇总

    10 19 去哪儿面试 1 struct和class的成员函数调用1000次后有什么执行效率方面的差异 xff1f 2 给两个int型数组A和B xff0c 长度都为n xff0c 编程实现A B 61 a1 b1 43 a2 b2 43
  • iOS8 新特性

    苹果公司在WWDC 2014上发布了许多新特性 xff0c 让我们一起来看看都有哪些内容 Contents App Extensions Touch ID Authentication Photos Games Health Kit Fra
  • 获取当前view所在页面的viewController

    一般来说 xff0c 我们可以知道一个viewController所在的view self view xff0c 或者它的子视图 self subViews 然而 xff0c 怎样知道一个view所在页面的viewController呢 x
  • [iOS] Get all UIView subviews with all property values

    转自StackOverFlow span class com style margin 0px padding 0px border 0px color rgb 128 128 128 background transparent span
  • Upgrading the delete confirmation button

    本文转载自andy heydon个人博客 ANDY HEYDON ARCHIVES ABOUT Upgrading the delete confirmation button by Andy iOS has a nice pattern
  • Linux系统的GPIO设置(以UpBoard为例)

    GPIO往往是通过sys文件系统进行操作的 xff0c 当我们需要验证一个GPIO口置1还是置0的话 xff0c 可以通过操作sys文件来完成 UpBoard官方所提供的linux系统已经安装了支持UP Board的RPi GPIO和相应的
  • ubuntu远程桌面

    xff08 一 xff09 可视化界面远程访问Linux服务器 这里以Ubuntu为例 xff0c 最常见的是通过xrdp和vnc这两种远程桌面协议来进行可视化远程操作 1 关于xrdp协议和vnc协议之间区别 参考自 xff1a http
  • 针对Linux 错误make: *** No rule to make target ` ‘, needed by xxx. Stop. (webots调试出现这个错误,原因相同)

    导致出现make No rule to make target 96 needed by xxx Stop 的主要原因就是因为Makefile出现问题 xff0c 编写Makefile的时候多加了空格 括号等原因导致报这个错误 具体的参考实

随机推荐

  • eigen库的安装与基本使用教程

    Eigen是可以用来进行线性代数 矩阵 向量操作等运算的C 43 43 库 xff0c 它里面包含了很多算法 在用C 43 43 写运动控制算法 xff08 例如MPC控制算法 xff09 的时候 由于算法包括矩阵运算 xff0c c 43
  • CMakeLists.txt的简单学习教程汇总

    最近因为要编辑一个T265的例程 xff0c 但是里面的CMakeLists中的含义自己不明白 xff0c 在网上搜集了一些资料 xff0c 对自己学习进行一下总结也是让需要的人更加明白清楚 学习这个的最好的方式是自己理解了以后 xff0c
  • LEGION联想Y7000P Ubuntu18.04的无线网卡驱动安装

    安装无线网卡的驱动的第一步大家应该弄清楚自己的无线网卡型号 建议最好的方式是在Windows下面确定类型 xff0c 在设备管理器中查看对应的无线适配器型号 xff0c 在下载对应的驱动 在Ubuntu下面也可以通过指令进行查看但是看不到具
  • 向量点乘(即内积)和叉乘(即外积、向量积)区别与意义分析

    向量之间的叉乘和点乘 xff0c 概念易混淆 xff0c 分别不清楚 xff0c 因此本文专门对这个概念进行了详细分析介绍 首先 xff0c 介绍一下向量 xff08 Vector xff09 xff0c 在几乎所有的几何问题中 xff0c
  • MATLAB图中加入阴影

    在绘制MATLAB 图时 xff0c 想表示不同的阶段 xff0c 所以将其中一部分用阴影颜色强调出来 xff0c 因此进行了一下绘制图像的知识补充 其中想要的效果是类似于下面这张 xff1a 具体如何实现呢 xff0c 有两种方式 xff
  • Matlab调整子图位置及大小

    为了绘制多个子图的MATLAB图 xff0c 但是使用导出设置时无法将子图全屏铺满整个屏幕 xff0c 因此本文对设置MATLAB子图位置进行了研究 xff0c 达到如下的效果 1 首先 xff0c 明确其中每个变量的含义 xff0c 从M
  • excel计算出均方根值(RMS)+ 均方根误差(RMSE)+标准差(Standard Deviation)

    首先弄明白这几者的区别 xff0c 方差 标准差和均方根误差的区别总结 均方根值 xff08 RMS xff09 43 均方根误差 xff08 RMSE xff09 43 标准差 xff08 Standard Deviation xff09
  • Matlab画图和点标记

    从csv中导出数据 xff0c 然后需要在MATLAB图中进行标记个别点 xff0c 但是利用MTALB自身标记的比较丑 xff0c 因此搜了一下别的方法 xff0c 具体效果如下 xff0c 其中的 可以改成O或者其他的自定义的符号 xf
  • word因导入mathtype不能使用复制粘贴快捷键的解决方法

    经查阅有两种解决方式 xff1a 1 直接删除你安装的原office中的MathType Commands 2016 dotm这个文件 2 是更换为mathtype里面的文件 xff0c 具体过程如下两个参考 xff1a 官网给出的解决办法
  • 强力推荐90个优秀外国英文网站

    一 大陆可访问的优秀英文信息源 1 英国 经济学家 http www economist com 2 美联社 http wire ap org GoToAP cgi 3 英国BBC http news bbc co uk 4 纽约时报 ht
  • 学习笔记(01):MFC上位机与STM32下位机通讯精讲-STM32串口实战1之串口发送1(串口初始化实践)...

    立即学习 https edu csdn net course play 6375 122556 1 GPIO PinAFConfig 函数复用功能 xff0c 将GPIO和USART连接起来
  • 单片机模拟输出PPM信号

    PPM信号就是将多个PWM信号放在一起传输 xff0c 一个PPM的周期为20ms 其中一个通道信号的范围为1 2ms 所以一个PPM信号 xff0c 最多可以传输10个通道的PWM信号 PPM信号以0 5ms的低电平信号代表一个通道的起始
  • linux在线模拟器

    我们项目部在开发过程中运用了自动化发布系统 xff0c 而且发布过程比较严格和规范 xff0c 写完代码只需要提交svn xff0c 填写发布文档 xff0c 测试通过之后有运维组发布到线上 这就导致很少有接触linux系统的机会 xff0
  • ROS订阅者程序

    include lt ros ros h gt include lt turtlesim Pose h gt include lt iomanip gt void poseMessageReceived const turtlesim Po
  • 吴恩达 ML作业提交:Grader sent no response

    目录 文章目录 目录前言正文解决方案 前言 最近在补习吴恩达machinelearning 的课程 xff0c 上完了课 xff0c 肯定是要做作业的 xff0c 做作业没有问题 xff0c 但在提交作业时遇到了问题 xff0c 记录如下
  • Docker容器通过独立IP暴露给局域网的方法

    Docker容器非常轻量 xff0c 系统开销非常少 xff0c 比VMware或者VirtualBox用起来方便 xff0c 部署起来也非常容易 官方推荐我们通过端口映射的方式把Docker容器的服务提供给宿主机或者局域网其他容器使用 一
  • CCS v6.1下完成TI-RTOS配置

    TI RTOS 是实时操作系统的TI微控制器 TI RTOS实现更快的发展不再需要开发人员编写和维护的系统软件 xff0c 如调度程序 xff0c 协议栈和驱动程序 它结合了实时多任务内核与其他中间件组件 xff0c 包括TCP IP和US
  • 【USRPx310系列(NI USRP2940-2955)+ srsRAN】环境搭建与应用

    x1f4e3 x1f973 x1f973 x1f973 x1f4e3 Hello 如果这篇 文章 对你有帮助 x1f604 xff0c 希望可以给博主点个赞 x1f44d 鼓励一下 x1f618 x1f4e3 x1f973 x1f973 x
  • 单相全桥逆变原理及仿真实验

    前言 一 单相全桥逆变器组成原理 1 全桥逆变电路拓扑结构 2 单相逆变器的SPWM调制方式 二 单相全桥逆变器仿真 1 SPWM调制波仿真 2 全桥逆变仿真 三 SPWM单片机程序实现 1 CubeMX配置 2 SPWM正弦表数据生成 3
  • STM32系列(HAL库)——使用ESP8266-01S物联网模块连接Onenet云平台上报DHT11温湿度

    前言 本篇主要讲解如何使用ESP8266 01S物联网模块连接Onenet云平台 xff0c 并上报DHT11模块的温湿度数据 本文单片机主控采用STM32F405RGT6 xff0c 使用其他主控的话基本要求有2个串口 xff0c 一个串