STM32连接-- 阿里云,OneNET(MQTT协议)详细教程

目录

MQTT协议

什么是物联网

什么是MQTT

MQTT运行机制

平台迭代 

微信公众号--星之援工作室 发送关键字(OneNet公共账号)

例程文件

关于如何连接阿里云

1.搭建云平台设备

1.1.平台选择 

1.2.创造产品

1.3.创造设备

2.查看设备参数(MQTT连接使用)

2.1.设备连接参数保存

2.2.主题的发布订阅

3.下位机代码编写

3.1.复用onenet的底层配置

4.连接测试

4.1.准备物件

4.2.连线图与修改参数

4.3.连接成功

关于如何连接OneNET

1.搭建云平台设备

1.1.协议选择

 1.2.添加产品

 1.3.添加设备

2.查看设备参数(MQTT连接使用)

4.连接测试

4.1.准备物件

4.2.连线图与修改参数

4.3.连接成功

 3.下位机代码编写

3.1.ESP8266.h

3.2.ESP8266.c

3.3.onenet.h

3.4.onenet.c

3.5.MqttKit.h

3.6.MqttKit.c

补充信息

 关于main函数的使用

关于如何实现Web端订阅可以查看这篇文章


MQTT协议

什么是物联网

物联网一词在2009年由Kevin Ashton首次使用。物联网指的是通过互联网来连接物理设备。物理设备可以相互之间通过互联网交换数据或由其他设备控制。物联网设备可以是冰箱、交通信号灯、工业控制系统等电子装置或电气设备。最常见的用例之一是传感器数据的收集,传输,分析和显示。工作人员可利用物联网数据实现远程监控台,或者对超过阈值的数据设置警报。

什么是MQTT

MQTT是一种轻量级消息传输协议,它为物联网设备提供了一种简单的方法来传输数据信息。由于MQTT占用网络资源小,且适用于远程信息传输,MQTT在物联网(IoT)领域起着重要作用。

MQTT协议的第一版由Andy Stanford-Clark(IBM)和Arlen Nipper(Cirrus Link)于1999年建立的。该协议最早应用于监控穿越沙漠的石油管道。因为设备是通过卫星链路连接的,所以当时MQTT所运行的网络带宽很小,且十分不稳定。而MQTT协议的设计目标也正是为了适用于这类传输距离远,带宽小,不稳定的网络环境。

MQTT运行机制

MQTT协议的中央通信中枢是MQTT服务器,它负责发送方和接收方间的信息通讯。每个向MQTT服务器发布消息的客户端都会在发布消息中包含一个主题。每个想要接收该消息的客户端都会订阅该主题。MQTT服务器在收到客户端向主题发布的信息后,会将信息发送给所有订阅该主题的客户端。这种体系结构可实现高度可扩展的解决方案,而数据生产者和数据使用者之间没有依赖关系。


OneNETicon-default.png?t=N7T8https://open.iot.10086.cn/console/

平台迭代 

现在OneNet4.14后不再维护多协议了
大家可以转战 阿里云 或者 华为云

这个文章没写华为云,后续空了我会添加上去~~~

今天找到一个新办法去用Onenet多协议

登录账号后若没有多协议功能,可通过这个网站进入多协议

PS:  现在One net不支持创建产品和设备了,只要使用之前建立的设备进行测试了哦 !!

https://open.iot.10086.cn/develop/global/product/#/public?protocol=3&other=1icon-default.png?t=N7T8https://open.iot.10086.cn/develop/global/product/#/public?protocol=3&other=1

现在多协议只对老用户开发,新注册的账号已经没有多协议选项了

若需要测试OneNet,可以私聊博主,博主可以提供一个公共账号进行测试!!!

阿里云还是可以直接放心使用的 ~ ~ ~

微信公众号--星之援工作室 发送关键字(OneNet公共账号)

➡️🫡🫡🫡🫡🫡🫡🫡🫡➡️

452c0cf75b1d4e4895194df8a5022c34.png (865×328)

例程文件

链接:MQTT-Onenet例程文件icon-default.png?t=N7T8https://pan.baidu.com/s/11KlzByF5sEBxxFpcOCyp7w?pwd=xzy0%C2%A0
提取码:xzy0

关于如何连接阿里云

1.搭建云平台设备

阿里云icon-default.png?t=N7T8https://www.aliyun.com/?accounttraceid=5df262f1b2db40f2b26ca21fd1f026bdgwje

 链接:创建视频以及物理模型icon-default.png?t=N7T8https://pan.baidu.com/s/1AsllLqDd1MljFonIWpKUxw?pwd=XZY0

1.1.平台选择 

 

1.2.创造产品

 

 

1.3.创造设备

 

2.查看设备参数(MQTT连接使用)

2.1.设备连接参数保存

2.2.主题的发布订阅

3.下位机代码编写

3.1.复用onenet的底层配置

4.连接测试

4.1.准备物件

1.stm32F103系列开发板

2.ESP8266模块

4.2.连线图与修改参数

ESP8266连接引脚

TX -- PA3        VCC -- 3.3V

RX -- PA2       GND -- GND

RST -- PB9

修改OenNET.c的连接参数,把之前保存的参数填写上去

使用的热点名称为 hhh  密码 12345678 (大家自行打开手机热点或者修改一下WiFi参数哦)

WIFi参数修改在esp8266.c
#define ESP8266_WIFI_INFO        "AT+CWJAP=\"hhh\",\"12345678\"\r\n"

#define ESP8266_ONENET_INFO      

"AT+CIPSTART=\"TCP\",\"iot-06z00e3auli0497.mqtt.iothub.aliyuncs.com\",1883\r\n"

4.3.连接成功

显示平台设备在线,只需要在添加另一台设备订阅相同主题即可实现消息的收发

 到此阿里云连接教程完成❤️

关于如何连接OneNET

1.搭建云平台设备

1.1.协议选择

 1.2.添加产品

 1.3.添加设备

 

 到这里我们就基本快完成云平台的搭建了

 

 

 到此云平台已搭建完成

2.查看设备参数(MQTT连接使用)

产品id

设备id

设备鉴权信息

 

 

4.连接测试

4.1.准备物件

1.stm32F103系列开发板

2.ESP8266模块

4.2.连线图与修改参数

ESP8266连接引脚

TX -- PA3        VCC -- 3.3V

RX -- PA2       GND -- GND

RST -- PB9

修改OenNET.c的连接参数,把之前保存的参数填写上去

使用的热点名称为 hhh  密码 12345678 (大家自行打开手机热点或者修改一下WiFi参数哦)

WIFi参数修改在esp8266.c
#define ESP8266_WIFI_INFO        "AT+CWJAP=\"hhh\",\"12345678\"\r\n"

#define ESP8266_ONENET_INFO        "AT+CIPSTART=\"TCP\",\"183.230.40.39\",6002\r\n"

4.3.连接成功

显示平台设备在线,只需要在添加另一台设备订阅相同主题即可实现消息的收发

 到此OneNET连接教程完成❤️

 3.下位机代码编写

3.1.ESP8266.h

#ifndef _ESP8266_H_
#define _ESP8266_H_

#include "sys.h"



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


void ESP8266_Init(void);
void Usart2_Init(unsigned int baud);
void ESP8266_Clear(void);

void ESP8266_SendData(unsigned char *data, unsigned short len);

unsigned char *ESP8266_GetIPD(unsigned short timeOut);
void Usart2_SendString(unsigned char *str, unsigned short len);

#endif

3.2.ESP8266.c

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

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

/* FreeRTOS头文件 */
#include "bsp_SysTick.h"
#include "usart.h"

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

#define ESP8266_WIFI_INFO		"AT+CWJAP=\"hhh\",\"12345678\"\r\n"

#define ESP8266_ONENET_INFO		"AT+CIPSTART=\"TCP\",\"183.230.40.39\",6002\r\n"


unsigned char esp8266_buf[128];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;


//==========================================================
//	函数名称:	ESP8266_Clear
//
//	函数功能:	清空缓存
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP8266_Clear(void)
{

	memset(esp8266_buf, 0, sizeof(esp8266_buf));
	esp8266_cnt = 0;

}

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

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

}

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

	while(time--)
	{
		if(ESP8266_WaitRecive() == REV_OK)							//如果收到数据
		{
			if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词
			{
				ESP8266_Clear();									//清空缓存
				
				return 0;
			}
		}
		
		Delay_ms(10);
	}
	
	return 1;

}

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

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

}

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

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

}
//==========================================================
//	函数名称:	USART2_IRQHandler
//
//	函数功能:	串口2收发中断
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void USART2_IRQHandler(void)
{

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断
	{
		if(esp8266_cnt >= sizeof(esp8266_buf))	esp8266_cnt = 0; //防止串口被刷爆
		esp8266_buf[esp8266_cnt++] = USART2->DR;
		
		USART_ClearFlag(USART2, USART_FLAG_RXNE);
	}

}
//==========================================================
//	函数名称:	ESP8266_Init
//
//	函数功能:	初始化ESP8266
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP8266_Init(void)
{
	GPIO_InitTypeDef GPIO_Initure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	//ESP8266复位引脚
	GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Initure.GPIO_Pin = GPIO_Pin_9;					//GPIOB1-复位
	GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_Initure);
	
	GPIO_WriteBit(GPIOB, GPIO_Pin_9, Bit_RESET);
	Delay_ms(100);
	GPIO_WriteBit(GPIOB, GPIO_Pin_9, Bit_SET);
	Delay_ms(100);
	
	ESP8266_Clear();

	printf("AT\r\n");
	while(ESP8266_SendCmd("AT\r\n\r", "OK", 200))
		Delay_ms(500);
	
	printf("CWMODE\r\n");
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK", 200))
		Delay_ms(500);
	
	printf("AT+CWDHCP\r\n");
	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK", 200))
		Delay_ms(500);
	
	printf("CWJAP\r\n");
	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP", 200))
		Delay_ms(500);
	
	printf("CIPSTART\r\n");
	while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT", 200))
		Delay_ms(500);
	
	printf("ESP8266 Init OK\r\n");
}


/*
************************************************************
*	函数名称:	Usart2_Init
*
*	函数功能:	串口2初始化
*
*	入口参数:	baud:设定的波特率
*
*	返回参数:	无
*
*	说明:		TX-PA2		RX-PA3
************************************************************
*/
void Usart2_Init(unsigned int baud)
{

	GPIO_InitTypeDef gpio_initstruct;
	USART_InitTypeDef usart_initstruct;
	NVIC_InitTypeDef nvic_initstruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	//PA2	TXD
	gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpio_initstruct.GPIO_Pin = GPIO_Pin_2;
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpio_initstruct);
	
	//PA3	RXD
	gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpio_initstruct.GPIO_Pin = GPIO_Pin_3;
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpio_initstruct);
	
	usart_initstruct.USART_BaudRate = baud;
	usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
	usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
	usart_initstruct.USART_Parity = USART_Parity_No;									//无校验
	usart_initstruct.USART_StopBits = USART_StopBits_1;								//1位停止位
	usart_initstruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
	USART_Init(USART2, &usart_initstruct);
	
	USART_Cmd(USART2, ENABLE);														//使能串口
	
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);									//使能接收中断
	
	nvic_initstruct.NVIC_IRQChannel = USART2_IRQn;
	nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
	nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvic_initstruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&nvic_initstruct);

}





/*
************************************************************
*	函数名称:	Usart_SendString
*
*	函数功能:	串口数据发送
*
*	入口参数:	USARTx:串口组
*				str:要发送的数据
*				len:数据长度
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void Usart2_SendString(unsigned char *str, unsigned short len)
{

	unsigned short count = 0;
	
	for(; count < len; count++)
	{
		USART_SendData(USART2, *str++);									//发送数据
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);		//等待发送完成
	}
}




3.3.onenet.h

#ifndef _ONENET_H_
#define _ONENET_H_





_Bool OneNet_DevLink(char *Tip);

void OneNet_SendData(char *Tip);
void OneNet_SendCmd(void);
void OneNet_RevPro(unsigned char *cmd);
_Bool OneNet_Subscribe(const char *topics[], unsigned char topic_cnt);
void OneNet_PacketPing(void);
_Bool OneNet_Publish(const char *topic, const char *msg);
void OneNet_HeartBeat(void);
#endif

3.4.onenet.c

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

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

//协议文件
#include "onenet.h"
#include "mqttkit.h"
#include "./SysTick/bsp_SysTick.h"

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

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

//全局变量
extern char *Tips ; //主题

#define PROID		"515377"   //产品ID

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

#define DEVID		"943294381"	//设备ID


extern unsigned char esp8266_buf[128];

extern unsigned char esp8266_buf[128];

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

	unsigned char *dataPtr;
	
	_Bool status = 1;
	
	printf("OneNet_DevLink\r\nPROID: %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)
	{
		ESP8266_SendData(mqttPacket._data, mqttPacket._len);			//上传平台
		
		dataPtr = ESP8266_GetIPD(250);									//等待平台响应
		if(dataPtr != NULL)
		{
			if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK)
			{
				switch(MQTT_UnPacketConnectAck(dataPtr))
				{
					case 0:printf("Tips:%s\r\n",Tip);
					status = 0;
					//LED2_ON;						//入网成功
					;break;
					
					case 1:printf("WARN:	连接失败:协议错误\r\n");break;
					case 2:printf("WARN:	连接失败:非法的clientid\r\n");break;
					case 3:printf("WARN:	连接失败:服务器失败\r\n");break;
					case 4:printf("WARN:	连接失败:用户名或密码错误\r\n");break;
					case 5:printf("WARN:	连接失败:非法链接(比如token非法)\r\n");break;
					
					default:printf("ERR:	连接失败:未知错误\r\n");break;
				}
			}
		}
		
		MQTT_DeleteBuffer(&mqttPacket);								//删包
	}
	else
		printf("WARN:	MQTT_PacketConnect Failed\r\n");
	
	return status;
	
}
u8 velue0 = 0;
u8 velue1 = 0;
unsigned char OneNet_FillBuf(char *buf)
{
	char text[32];
	
	memset(text, 0, sizeof(text));
	
	strcpy(buf, ",;");
		
	memset(text, 0, sizeof(text));
	sprintf(text, "Blue_Led,%d;", velue0);
	strcat(buf, text);
	
	memset(text, 0, sizeof(text));
	sprintf(text, "Yellow_Led,%d;", velue1);
	strcat(buf, text);
	
	return strlen(buf);
}

//==========================================================
//	函数名称:	OneNet_SendData
//
//	函数功能:	上传数据到平台
//
//	入口参数:	type:发送数据的格式
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void OneNet_SendData(char *Tip)
{
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};												//协议包
	
	char buf[128];
	
	short body_len = 0, i = 0;
	
	//printf("Tips:%s\r\n",Tip);
	
	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];
			
			ESP8266_SendData(mqttPacket._data, mqttPacket._len);									//上传数据到平台
			//printf("Send %d Bytes\r\n", mqttPacket._data);
			
			MQTT_DeleteBuffer(&mqttPacket);															//删包
		}
		else
			printf("WARN:	EDP_NewBuffer Failed\r\n");
	}
	
}
//==========================================================
//	函数名称:	OneNet_Publish
//
//	函数功能:	发布消息
//
//	入口参数:	topic:发布的主题
//				msg:消息内容
//
//	返回参数:	0-成功	1-需要重送
//
//	说明:		
//==========================================================
_Bool OneNet_Publish(const char *topic, const char *msg)
{

	//Delay_ms(100);
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};							//协议包
	
	//printf( "Publish Topic: %s, Msg: %s\r\n", topic, msg);
	
	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, topic, msg, strlen(msg), MQTT_QOS_LEVEL2, 0, 1, &mqttPacket) != 1)
	{

		ESP8266_SendData(mqttPacket._data, mqttPacket._len);					//向平台发送订阅请求
		MQTT_DeleteBuffer(&mqttPacket);											//删包
	}
	return 0;

}
//==========================================================
//	函数名称:	OneNet_Subscribe
//
//	函数功能:	订阅
//
//	入口参数:	topics:订阅的topic
//				topic_cnt:topic个数
//
//	返回参数:	SEND_TYPE_OK-成功	SEND_TYPE_SUBSCRIBE-需要重发
//
//	说明:		
//==========================================================
_Bool OneNet_Subscribe(const char *topics[], unsigned char topic_cnt)
{
	
	unsigned char i = 0;
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};							//协议包
	
	for(; i < topic_cnt; i++)
		printf( "Subscribe Topic: %s\r\n", topics[i]);
	
	if(MQTT_PacketSubscribe(MQTT_SUBSCRIBE_ID, MQTT_QOS_LEVEL2, topics, topic_cnt, &mqttPacket) == 0)
	{
		ESP8266_SendData(mqttPacket._data, mqttPacket._len);					//向平台发送订阅请求
		
		MQTT_DeleteBuffer(&mqttPacket);											//删包
	}
  return 0;
}

//==========================================================
//	函数名称:	OneNet_HeartBeat
//
//	函数功能:	心跳检测
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void OneNet_HeartBeat(void)
{
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};
	
	unsigned char sCount = 3;
	
//---------------------------------------------步骤一:组包---------------------------------------------
	if(MQTT_PacketPing(&mqttPacket))
		return;
	
	while(sCount--)
	{
//---------------------------------------------步骤二:发送数据-----------------------------------------
		ESP8266_SendData(mqttPacket._data, mqttPacket._len);
	  //while(OneNet_DevLink(Tips))
---------------------------------------------步骤三:解析返回数据-------------------------------------
//		if(MQTT_UnPacketRecv(cmd) == MQTT_PKT_PINGRESP)
//		{
//			printf( "Tips:	HeartBeat OK\r\n");
//			
//			break;
//		}
//		else
//		{
//			//ESP8266_Init();					//初始化ESP8266
//			printf("Check Device\r\n");
//		}
		
		Delay_ms(10);
	}
	
//---------------------------------------------步骤四:删包---------------------------------------------
	MQTT_DeleteBuffer(&mqttPacket);

}
/**
  * @brief  检测字符长度并提取透传
  * @param  无
  * @retval 无
  */
char my_strlen(int8 **payload)//?const?????
{
	static char cmd[200];
	int i=0;
	while(**payload)
	{
		cmd[i] = **payload;
		i++;
		payload++;
		printf("%d\n",cmd[i]);
	}

	printf("%c\n",cmd[100]);
	printf("%c%c%c%c\n",cmd[111],cmd[112],cmd[113],cmd[114]);
	return cmd[11];
}
//==========================================================
//	函数名称:	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 topic_len = 0;
	unsigned short req_len = 0;
	
	unsigned char type = 0;
	unsigned char qos = 0;
	static unsigned short pkt_id = 0;
	
	short result = 0;

	char *dataPtr = NULL;
	char numBuf[10];
	int num = 0;
	uint16_t ID = 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)
			{
				printf( "cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);
				
				if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0)	//命令回复组包
				{
					printf( "Tips:	Send CmdResp\r\n");
					
					ESP8266_SendData(mqttPacket._data, mqttPacket._len);			//回复命令
					MQTT_DeleteBuffer(&mqttPacket);									//删包
				}
			}
		
		break;
			
		case MQTT_PKT_PUBLISH:														//接收的Publish消息
		
			result = MQTT_UnPacketPublish(cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id);
			if(result == 0)
			{
				printf( "topic: %s, topic_len: %d, payload: %s, payload_len: %d\r\n",
																	cmdid_topic, topic_len, req_payload, req_len);
	
				switch(qos)
				{
					case 1:															//收到publish的qos为1,设备需要回复Ack
					
						if(MQTT_PacketPublishAck(pkt_id, &mqttPacket) == 0)
						{
							printf( "Tips:	Send PublishAck\r\n");
							ESP8266_SendData(mqttPacket._data, mqttPacket._len);
							MQTT_DeleteBuffer(&mqttPacket);
						}
					
					break;
					
					case 2:															//收到publish的qos为2,设备先回复Rec
																					//平台回复Rel,设备再回复Comp
						if(MQTT_PacketPublishRec(pkt_id, &mqttPacket) == 0)
						{
							printf( "Tips:	Send PublishRec\r\n");
							ESP8266_SendData(mqttPacket._data, mqttPacket._len);
							MQTT_DeleteBuffer(&mqttPacket);
						}
					
					break;
					
					default:
						break;
				}
			}
		
		break;
			
		case MQTT_PKT_PUBACK:														//发送Publish消息,平台回复的Ack
		
			if(MQTT_UnPacketPublishAck(cmd) == 0)
				printf( "Tips:	MQTT Publish Send OK\r\n");
			
		break;
			
		case MQTT_PKT_PUBREC:														//发送Publish消息,平台回复的Rec,设备需回复Rel消息
		
			if(MQTT_UnPacketPublishRec(cmd) == 0)
			{
				printf( "Tips:	Rev PublishRec\r\n");
				if(MQTT_PacketPublishRel(MQTT_PUBLISH_ID, &mqttPacket) == 0)
				{
					printf( "Tips:	Send PublishRel\r\n");
					ESP8266_SendData(mqttPacket._data, mqttPacket._len);
					MQTT_DeleteBuffer(&mqttPacket);
				}
			}
		
		break;
			
		case MQTT_PKT_PUBREL:														//收到Publish消息,设备回复Rec后,平台回复的Rel,设备需再回复Comp
			
			if(MQTT_UnPacketPublishRel(cmd, pkt_id) == 0)
			{
				printf( "Tips:	Rev PublishRel\r\n");
				if(MQTT_PacketPublishComp(MQTT_PUBLISH_ID, &mqttPacket) == 0)
				{
					printf( "Tips:	Send PublishComp\r\n");
					ESP8266_SendData(mqttPacket._data, mqttPacket._len);
					MQTT_DeleteBuffer(&mqttPacket);
				}
			}
		
		break;
		
		case MQTT_PKT_PUBCOMP:														//发送Publish消息,平台返回Rec,设备回复Rel,平台再返回的Comp
		
			if(MQTT_UnPacketPublishComp(cmd) == 0)
			{
				printf( "Tips:	Rev PublishComp\r\n");
			}
		
		break;
			
		case MQTT_PKT_SUBACK:														//发送Subscribe消息的Ack
		
			if(MQTT_UnPacketSubscribe(cmd) == 0)
				printf( "Tips:	MQTT Subscribe OK\r\n");
			else
				printf( "Tips:	MQTT Subscribe Err\r\n");
		
		break;
			
		case MQTT_PKT_UNSUBACK:														//发送UnSubscribe消息的Ack
		
			if(MQTT_UnPacketUnSubscribe(cmd) == 0)
				printf( "Tips:	MQTT UnSubscribe OK\r\n");
			else
				printf( "Tips:	MQTT UnSubscribe Err\r\n");
		
		break;
		
		default:
			result = -1;
		break;
	}
	
	ESP8266_Clear();									//清空缓存
	
	if(result == -1)
		return;
	
		dataPtr = strchr(req_payload, ':');					//搜索':'

	if(dataPtr != NULL && result != -1)					//如果找到了
	{
		dataPtr++;
		printf("%s",Tips);
		while(*dataPtr >= '0' && *dataPtr <= '9')		//判断是否是下发的命令控制数据
		{
			numBuf[num++] = *dataPtr++;
		}
		numBuf[num] = 0;
		
		num = atoi((const char *)numBuf);				//转为数值形式
		printf( "num:%d\r\n",num);
		if(strstr((char *)req_payload, "LED"))		//搜索"redled"
		{
			//LED
		
			//Mqtt_LED(Tips,num);
		}
		else if(strstr((char *)req_payload, "TOUCH"))
		{
			//指纹
			dataPtr = strchr(req_payload, '-');					//搜索'-'
			if(dataPtr != NULL && result != -1)					//如果找到了
			{
				dataPtr++;
				while(*dataPtr >= '0' && *dataPtr <= '9')		//判断是否是下发的命令控制数据
				{
					numBuf[ID++] = *dataPtr++;
				}
				numBuf[ID] = 0;
				ID = atoi((const char *)numBuf);				//转为数值形式
				printf("ID:%d\r\n",ID);
				//Mqtt_Task( Tips, num, ID);
			}else{
				//Mqtt_Task(Tips, num, ID);
			}
			
		}
		else if(strstr((char *)req_payload, "DOOR"))
		{
			//步进电机
			//Door(Tips,num);
		}
		

	}

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

}

最后MQTT协议使用引用他人

3.5.MqttKit.h

#ifndef _MQTTKIT_H_
#define _MQTTKIT_H_


#include "Common.h"


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

#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

3.6.MqttKit.c

补充信息

 关于main函数的使用

//硬件初始化
static void Hardware_Init(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	
	SysTick_Init();			//延时函数初始化
	
	USART_Config();	//串口1初始化为115200
	Usart2_Init(115200); 	//串口2,驱动ESP8266用
//	BEEP_Config();
//	DHT11_Init();
//	ADCx_Init();

}

static void Net_Init()
{
	ESP8266_Init();					//初始化ESP8266

	Delay_ms(10);
	while(OneNet_DevLink(Tips))			//接入OneNET
		Delay_ms(100);
	OneNet_Subscribe(topics, 1);
   
}
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{
	unsigned char *dataPtr = NULL;
	unsigned short timeCount = 0;	//发送间隔变量
	unsigned short timeDoor = 0;	//发送间隔变量
	Hardware_Init();				//初始化外围硬件
	
	Delay_ms(500);   /* 延时500个tick */

	Net_Init();						//网络初始化

	
	
	while(1)
	{

		timeDoor ++;

		dataPtr = ESP8266_GetIPD(0);
		if(dataPtr != NULL)
		{
			//从收到信息开始算起
			timeCount = 0;
			OneNet_RevPro(dataPtr);
		
		}else if(timeCount >= 100)	//发送间隔
		{

			//每两秒询问指纹状态,自动关门
			sprintf((char*)string,"temp:%s humi:%s MQ_2:%s MQ_4:%s MQ_135:%s",temp,humi,MQ_2,MQ_4,MQ_135);
			printf("%s\n",string);
			OneNet_Subscribe(topics, 1);
			//心跳包
			while(OneNet_Publish( Tips , string));
		
			timeCount = 0;
		}

		



	}	

 
  
}

关于如何实现Web端订阅可以查看这篇文章

WebSocket连接MQTT方案之阿里云及其它平台通解

 注:转载请标明出处!

### 回答1: STM32使用ESP8266连接OneNET使用MQTT协议的步骤如下: 1. 首先,确保STM32和ESP8266之间的硬件连接正确。将ESP8266的TX引脚连接STM32的RX引脚,将ESP8266的RX引脚连接STM32的TX引脚,并将GND引脚连接到共地。 2. 接下来,需要编写STM32的固件代码。首先,需要初始化串口通信接口,并将其配置为与ESP8266的通信接口相匹配。其次,需要配置STM32的GPIO引脚,将其用于控制ESP8266的工作模式切换(例如,将ESP8266切换到STA模式或AP模式)。然后,使用串口通信接口与ESP8266进行AT指令的交互,以设置ESP8266的连接参数和网络配置。最后,使用STM32MQTT库来实现与OneNET连接和数据传输。 3. 在ESP8266上,需要使用AT指令配置ESP8266的网络连接MQTT参数。可以使用AT+CWMODE指令将ESP8266切换到STA模式,并使用AT+CWJAP指令连接到WiFi网络。然后,使用AT+CIPSTART指令建立与OneNETMQTT服务器的连接,并使用AT+CIPSEND指令发送MQTT消息。 4. 一旦STM32成功连接OneNETMQTT服务器,就可以使用STM32MQTT库来发送和接收数据。可以使用MQTT的发布(Publish)和订阅(Subscribe)功能,向OneNET发送数据或接收来自OneNET的数据。 总结来说,使用STM32连接OneNETMQTT服务器需要进行硬件连接和固件代码的编写,而ESP8266则需要使用AT指令配置网络连接MQTT参数。之后,STM32可以使用MQTT库来实现与OneNET的数据传输。 ### 回答2: 要使用STM32与ESP8266连接OneNet并使用MQTT协议,我们可以采取以下步骤: 1. 在STM32上配置串口通信:将STM32通过UART配置为与ESP8266进行串口通信的方式。设置合适的波特率、数据位、停止位和奇偶校验位等。 2. 连接ESP8266和STM32:根据ESP8266的硬件连接方式(一般为串口连接),将ESP8266的TX线连接STM32的RX线,将ESP8266的RX线连接STM32的TX线。还需将ESP8266的VCC和GND引脚分别连接STM32的电源线和地线。 3. 配置ESP8266连接OneNet:ESP8266需要连接OneNet,并使用MQTT协议进行通信。通过AT指令,配置ESP8266的WiFi连接,设置SSID和密码。然后使用AT+CIPSTART指令连接OneNetMQTT服务器。 4. 配置STM32发送和接收数据:在STM32上配置串口发送和接收功能,以便与ESP8266进行通信。使用UART发送指令字节流给ESP8266并接收ESP8266的响应。 5. 使用MQTT协议OneNet通信:在STM32上通过串口向ESP8266发送MQTT协议指令,例如建立连接(CONNECT),订阅主题(SUBSCRIBE),发布消息(PUBLISH),取消订阅(UNSUBSCRIBE)等。根据需求进行合适的MQTT操作。 6. 处理OneNet的响应和数据:在STM32上解析和处理来自OneNet的响应和数据。根据MQTT协议,您可以接收和解析来自OneNet的订阅消息。 通过以上步骤,您就可以在STM32上使用ESP8266连接OneNet并使用MQTT协议进行通信和数据传输。 ### 回答3: STM32是一种常用的微控制器,而ESP8266是一种常用的Wi-Fi模块。这两者可以结合使用,通过使用MQTT协议连接OneNet平台。 首先,我们需要在STM32上配置USART或SPI接口与ESP8266通信。然后,我们可以使用AT指令集来与ESP8266进行通信。通过发送相应的AT指令,我们可以实现与ESP8266的Wi-Fi连接。这将使STM32具备互联网连接功能。 接下来,我们需要使用MQTT协议OneNet平台进行连接。我们可以使用一个MQTT客户端库,例如MQTTFX或Paho,来处理MQTT通信。在STM32上,我们可以使用相应的库或手动实现MQTT协议来处理与OneNet的通信。 在连接OneNet之前,我们需要在OneNet平台上创建一个设备,并获取相应的设备ID和API密钥。这些信息将用于在我们的STM32代码中进行身份验证和连接。 一旦连接OneNet,我们可以通过使用MQTT发布者/订阅者机制在设备和OneNet之间进行通信。我们可以发布传感器数据或接收来自OneNet的命令。这样,我们可以实现远程监控和控制功能。 在代码实现方面,我们需要处理与ESP8266的通信、MQTT协议的处理以及与OneNet的通信。我们可以使用适当的库和API来简化代码实现过程。 综上所述,通过将STM32与ESP8266和OneNet相结合,使用MQTT协议进行通信,我们可以实现STM32OneNet平台之间的连接和数据传输。这为物联网应用提供了一个便捷的方式,使得我们可以远程监控和控制STM32设备。
评论 73
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿柒学起来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值