利用MQTT协议连接阿里云物联网平台

点击查看代码
/**
   *********************************************************************************
   * @file    main.c 
   * @author  
   * @version 
   * @date    2024/07/23
   * @brief   
						  
   *********************************************************************************
**/

#include "stm32f4xx.h"  //必须包含
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"

uint8_t  u3_recvbuf[512] 	= {0};	//WIFI的接收缓冲区
uint32_t u3_recvcnt = 0;					//接收缓冲器的计数器

uint8_t  u3_sendbuf[1024] = {0};	//WIFI的发送缓冲区
uint32_t u3_sendcnt = 0;				  //发送缓冲器的计数器

#define  BYTE0(data)    ( *( (char *)&data + 0 ) )
#define  BYTE1(data)    ( *( (char *)&data + 1 ) )
#define  BYTE2(data)    ( *( (char *)&data + 2 ) )
#define  BYTE3(data)    ( *( (char *)&data + 3 ) )

//需要根据自己的修改
#define  CLIENT_ID  "k1ltu6J15a3.dht11|securemode=2,signmethod=hmacsha256,timestamp=1721893050123|"
#define  USERNAME		"dht11&k1ltu6J15a3"
#define  PASSWD     "bd56fb03f88bd2c5f3aad6035a3f467f5e98d4d3a37bfa8091c05398b8d46ed0"

#define  PUBLISH_TOPIC  "/sys/k1ltu6J15a3/dht11/thing/event/property/post"

//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void USART1_IRQHandler(void)
{
	uint8_t data;
  //判断中断是否发生
  if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  {   
		//从USART1中接收一个字节
		data = USART_ReceiveData(USART1);  //一次只能接收一个字节   
		
		//把接收到的数据转发出去
		USART_SendData(USART1,data);
  }
}

//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void USART3_IRQHandler(void)
{
	
  //判断中断是否发生
  if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
  {   
		//从USART3中接收一个字节
		u3_recvbuf[u3_recvcnt++] = USART_ReceiveData(USART3);  //一次只能接收一个字节   
  }
}


//延时微秒 注意:Systick是24bit的递减计数器  约等于798915us,所以参数不可以超过这个值
void delay_us(u32 nus)
{
	SysTick->CTRL = 0; 						 // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
	SysTick->LOAD = (nus * 21) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
	SysTick->VAL  = 0; 						 // 清除当前数值寄存器的值
	SysTick->CTRL = 1; 						 // 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
	while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
	SysTick->CTRL = 0; 						 // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器

}

//延时毫秒 注意:Systick是24bit的递减计数器  约等于798ms,所以参数不可以超过这个值
void delay_ms(u32 nms)
{
	SysTick->CTRL = 0; 						 			// 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
	SysTick->LOAD = (nms * 21*1000) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
	SysTick->VAL  = 0; 						 			// 清除当前数值寄存器的值
	SysTick->CTRL = 1; 						 			// 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
	while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
	SysTick->CTRL = 0; 						 			// 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
}



void USART1_Config(u32 baud)
{
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//打开了GPIO端口时钟  PA9和PA10
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//打开USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//选择GPIO引脚的复用功能
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
	
	//配置GPIO引脚 注意:复用模式
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9|GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//配置串口参数+对串口初始化
	USART_InitStructure.USART_BaudRate = baud;																		//波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;										//数据位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;												//停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;														//无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 				//无流控
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;									//收发模式
	USART_Init(USART1, &USART_InitStructure);

	//配置NVIC参数 + 对NVIC初始化
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	//选择USART1的中断源,接收到数据则触发中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	//打开串口
	USART_Cmd(USART1, ENABLE);
}

void USART3_Config(u32 baud)
{
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//打开了GPIO端口时钟  PB10和PB11
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	//打开USART3的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	
	//选择GPIO引脚的复用功能
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource11 , GPIO_AF_USART3);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource10 , GPIO_AF_USART3);
	
	//配置GPIO引脚 注意:复用模式
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_11|GPIO_Pin_10;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	//配置串口参数+对串口初始化
	USART_InitStructure.USART_BaudRate = baud;																		//波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;										//数据位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;												//停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;														//无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 				//无流控
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;									//收发模式
	USART_Init(USART3, &USART_InitStructure);

	//配置NVIC参数 + 对NVIC初始化
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	//选择USART3的中断源,接收到数据则触发中断
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
	
	//打开串口
	USART_Cmd(USART3, ENABLE);
}

//利用串口发送一个字符串
void  USART1_SendString(const char *str)
{
	while(*str)
	{
		 USART_SendData(USART1,*str++);
		 while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );		
	}
}

//利用串口发送一个字符串
void  USART3_SendString(const char *str)
{
	while(*str)
	{
		 USART_SendData(USART3,*str++);
		 while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET );		
	}
}

//利用串口发送n字节
void  USART3_SendBytes(const char *str,uint32_t len)
{
	while(len--)
	{
		 USART_SendData(USART3,*str++);
		 while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET );		
	}
}

//MQTT的CONNECT报文,目的是用于连接服务器,并且该报文必须是第一个
bool mqtt_connect(char *clientid,char *username,char *passwd)
{
	uint32_t cnt = 0;
	
	uint32_t clientid_len = strlen(clientid); //客户端id的长度
	uint32_t username_len = strlen(username); //用户名的长度
	uint32_t passwd_len   = strlen(passwd);   //密码的长度
	
	//用于存储剩余长度 剩余长度 = 可变报头(10) + 有效载荷(客户端id长度 + 2 + 用户名长度 + 2 + 密码长度 + 2)
	uint32_t remain_length = 10 + (2+clientid_len) + (2+username_len) + (2+passwd_len); 
	

	//1.对发送/缓冲区进行初始化
	memset((char *)u3_sendbuf,0,1024);
	u3_sendcnt = 0;
	

	//2.固定报头
	u3_sendbuf[u3_sendcnt++] = 0x10;  //CONNECT
	
	//3.对剩余长度进行编码
	do
	{
		uint8_t encodedByte = remain_length % 128;
		
		remain_length = remain_length / 128;
		
		// if there are more data to encode, set the top bit of this byte
		if ( remain_length > 0 )
		{
			encodedByte = encodedByte | 128;
		}
		
		u3_sendbuf[u3_sendcnt++] = encodedByte;
	} 
  while ( remain_length > 0 );
	
	//4.可变报头
	u3_sendbuf[u3_sendcnt++] = 0;  	 //协议名称
	u3_sendbuf[u3_sendcnt++] = 4; 
	u3_sendbuf[u3_sendcnt++] = 'M'; 
	u3_sendbuf[u3_sendcnt++] = 'Q'; 
	u3_sendbuf[u3_sendcnt++] = 'T';  
	u3_sendbuf[u3_sendcnt++] = 'T';  
	u3_sendbuf[u3_sendcnt++] = 4;     //协议版本
	u3_sendbuf[u3_sendcnt++] = 0xC2;  //连接标志   
	u3_sendbuf[u3_sendcnt++] = 0;  	 //保持连接
	u3_sendbuf[u3_sendcnt++] = 120;   //保持2分钟
	
	//5.有效载荷  都是字符串  每个字符串前面都有2字节用于表示字符串长度   客户端id  用户名  密码
	u3_sendbuf[u3_sendcnt++] = BYTE1(clientid_len);  	 //MSB
	u3_sendbuf[u3_sendcnt++] = BYTE0(clientid_len);     //LSB
	memcpy(&u3_sendbuf[u3_sendcnt],clientid,clientid_len);
	u3_sendcnt += clientid_len;
	
	u3_sendbuf[u3_sendcnt++] = BYTE1(username_len);  	 //MSB
	u3_sendbuf[u3_sendcnt++] = BYTE0(username_len);     //LSB
	memcpy(&u3_sendbuf[u3_sendcnt],username,username_len);
	u3_sendcnt += username_len;
	
	u3_sendbuf[u3_sendcnt++] = BYTE1(passwd_len);  	  //MSB
	u3_sendbuf[u3_sendcnt++] = BYTE0(passwd_len);      //LSB
	memcpy(&u3_sendbuf[u3_sendcnt],passwd,passwd_len);
	u3_sendcnt += passwd_len;
	
	//7.等待接收服务器的响应报文
	while(1)
	{
		
		memset((char *)u3_recvbuf,0,512);
		u3_recvcnt = 0;
		
		//6.把CONNECT报文发送
		USART3_SendBytes((char *)u3_sendbuf,u3_sendcnt); 
	  USART1_SendString("send ok\r\n"); //为了测试
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		
		if(u3_recvbuf[0] == 0x20 && u3_recvbuf[1] == 0x02)
		{
			//成功
			if(u3_recvbuf[3] == 0x00)
			{
				USART1_SendString("连接已接受,连接已被服务端接受\r\n"); //为了测试
				return true;
			}
			//异常
			else
			{			
				switch(u3_recvbuf[3])
				{
					case 0x01:  USART1_SendString("连接已拒绝,不支持的协议版本\r\n");  break;
					case 0x02:  USART1_SendString("连接已拒绝,不合格的客户端标识符\r\n"); break;
					case 0x03:  USART1_SendString("连接已拒绝,服务端不可用\r\n"); break;
					case 0x04:  USART1_SendString("连接已拒绝,无效的用户名或密码\r\n");  break;
					case 0x05:  USART1_SendString("连接已拒绝,未授权\r\n");  break;
				}	
			}			
		}
	}
	
	return false;
}

//发布   服务等级固定=0,则不需要报文标志符,另外服务器也不会进行响应
void  mqtt_publish(char *topic,char *databuf)
{
	uint32_t cnt = 0;
	
	uint32_t topic_len   = strlen(topic);   //主题的长度
	uint32_t databuf_len = strlen(databuf); //有效载荷的长度
	
	//用于存储剩余长度 剩余长度 = 可变报头 + 有效载荷
	uint32_t remain_length = (2+topic_len) + (databuf_len); 
	

	//1.对发送/缓冲区进行初始化
	memset((char *)u3_sendbuf,0,1024);
	u3_sendcnt = 0;
	

	//2.固定报头
	u3_sendbuf[u3_sendcnt++] = 0x30;  //PUBLISH
	
	//3.对剩余长度进行编码
	do
	{
		uint8_t encodedByte = remain_length % 128;
		
		remain_length = remain_length / 128;
		
		// if there are more data to encode, set the top bit of this byte
		if ( remain_length > 0 )
		{
			encodedByte = encodedByte | 128;
		}
		
		u3_sendbuf[u3_sendcnt++] = encodedByte;
	} 
  while ( remain_length > 0 );
	
	//4.可变报头
	u3_sendbuf[u3_sendcnt++] = BYTE1(topic_len);  	 //MSB
	u3_sendbuf[u3_sendcnt++] = BYTE0(topic_len);     //LSB
	memcpy(&u3_sendbuf[u3_sendcnt],topic,topic_len);
	u3_sendcnt += topic_len;
	
	//5.有效载荷
	memcpy(&u3_sendbuf[u3_sendcnt],databuf,databuf_len);
	u3_sendcnt += databuf_len;
	
	//6.把PUBLISH报文发送
	USART3_SendBytes((char *)u3_sendbuf,u3_sendcnt); 
	USART1_SendString(" publish send ok\r\n"); //为了测试
}


void mqtt_keepalive(void)
{
	uint8_t buf[2] ={0xC0,0x00};
	
	//1.对发送/缓冲区进行初始化
	memset((char *)u3_sendbuf,0,1024);
	u3_sendcnt = 0;
	
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	
	USART3_SendBytes((char *)buf,2); 
	
	if(u3_recvbuf[0] == 0xD0 && u3_recvbuf[1] == 0x00)
	{	
		USART1_SendString("心跳响应\r\n"); //为了测试
	}
}

int main()
{

	
	//1.硬件的初始化
	USART1_Config(9600);
  USART3_Config(115200);
	
	//退出透传  +++
	USART3_SendString("+++");  				
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	
	//2.配置ESP8266参数
  USART3_SendString("AT\r\n");  										//测试指令
	delay_ms(500);
	delay_ms(500);
	
	USART1_SendString((char *)u3_recvbuf);
	
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	
	//设置模式  STA
	USART3_SendString("AT+CWMODE_CUR=1\r\n");  				
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	USART1_SendString((char *)u3_recvbuf);
	
	//热点名称:lmx  热点密码:12345678
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	USART3_SendString("AT+CWJAP_DEF=\"lmx\",\"12345678\"\r\n");  				//连接热点 需要修改
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	
	USART1_SendString((char *)u3_recvbuf);
	
	
	//连接服务器,阿里云物联网平台的服务器的URL:iot-06z00iiy4zswde1.mqtt.iothub.aliyuncs.com  端口:1883
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	USART3_SendString("AT+CIPSTART=\"TCP\",\"iot-06z00hfdtkxecfe.mqtt.iothub.aliyuncs.com\",1883\r\n"); //需要修改
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	USART1_SendString((char *)u3_recvbuf);
	
	
	//使能透传
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	USART3_SendString("AT+CIPMODE=1\r\n");  				//进入透传  >出现之后,才表示进入透传
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	USART1_SendString((char *)u3_recvbuf);
	
	//进入透传
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	USART3_SendString("AT+CIPSEND\r\n");  				//进入透传  >出现之后,才表示进入透传
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	USART1_SendString((char *)u3_recvbuf);
	
	//发送CONNECT
	memset((char *)u3_recvbuf,0,512);
	u3_recvcnt = 0;
	mqtt_connect(CLIENT_ID,USERNAME,PASSWD);
	
	
	
	
	

	while(1)
	{
		//数据上报  JSON格式
		mqtt_publish(PUBLISH_TOPIC,"{\"id\":\"123\",\"version\":\"1.0\",\"params\":{\"temp\":20},\"method\":\"thing.event.property.post\"}");
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		delay_ms(500);
		
		mqtt_keepalive();
	}
}





posted @ 2025-08-30 12:38  w1888  阅读(1)  评论(0)    收藏  举报