mqtt与云服务器

news2025/2/24 20:58:16

mqtt

目录

mqtt

回顾

云服务器的操作

MQTT协议

-- 将官方库移植到工程

-- 应用

-- 可能会出现的问题:

完整代码


回顾

-- 昨天我们写的AT指令是直接写在main中,在while循环的外面,没有很好的封装,所以今天我们写一个函数来封装AT指令

	//要保证能在while循环中运行
uint8_t state = 0;
void wifi_get_time(void)
{

	uint8_t back = 0;
	switch(state)
	{
		case 0:
			back = SendCmdAndJudgeSuccess("AT\r\n","OK",1000);
		if(back == 1)//返回值如果是1,代表指令执行成功
			state++;
		break;
		case 1:
			back = SendCmdAndJudgeSuccess("AT+RST\r\n","OK",2000);
		if(back == 1)
			state++;
		break;
		case 2:
			back = SendCmdAndJudgeSuccess("AT+CWMODE=1\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 3:
			back = SendCmdAndJudgeSuccess("AT+CIPMUX=0\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 4:
			//在flash里面读取wifi信息esp.wifiname,esp.wifipassword,这里没有用flash,先直接赋值
			strcpy(esp.wifiname,"111"); 
			strcpy(esp.wifipassword,"pimouren"); 
			memset(esp.txbuff,0,1024);
			sprintf(esp.txbuff,"AT+CWJAP=\"%s\",\"%s\"\r\n",esp.wifiname,esp.wifipassword);
			back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
		if(back == 1)
			state++;
		break;
		case 5:
			memset(esp.txbuff,0,1024);
			//sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",TIMEIP,TIMEPORT);
		if(back == 1)
			state++;
		break;
		case 6:
			back = SendCmdAndJudgeSuccess("AT+CIPMODE=1\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 7:
			back = SendCmdAndJudgeSuccess("AT+CIPSEND\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 8:
			memset(esp.rxbuff,0,1024);
			esp.rxlen = 0;
			esp.rxflag = 0;
			memset(esp.txbuff,0,1024);
			sprintf(esp.txbuff,"%s",GETTIME);	
			uart3_txstr(esp.txbuff);
			Delay_nms(1000);
			state++;

			break;
		case 11:
			back = SendCmdAndJudgeSuccess("AT+CIPCLOSE\r\n","OK",1000);
			if(back == 1)
			state++;
		break;
	}
}

云服务器的操作

-- 云服务器有公有的(阿里云。。)和私有的(公司单独的)。

  • 1、和服务器进行连接(最简单的就是tcp连接,发送请求指令)

有一些服务器通信是比较复杂了
有的通信还要遵循一些协议
比如说mqtt协议

  • 2、如何跟服务器通信

-- 阿里云有很多产品,具体用哪个 -- 打开阿里云,注册并登入,从产品里面选择物联网找到飞燕平台

alt text

-- 进入点击管理控制台 

alt text

-- 注意:进不去就说明账号之前使用过,需要重新注册账号

-- 点击创建新项目 

alt text

-- 双击创建好的项目 

alt text

-- 点击创建产品 

alt text

-- 填写相关信息 

alt text

alt text

-- 其他就不用改了,随后点击确认

-- 添加自定义功能 

alt text

 

alt text

-- 随后在人机交互模块

alt text

-- 配置基础APP 

alt text

-- 

alt text

-- 在设备模块模块点击选择面板 

alt text

-- 注意这里APP的模块官方会提供一些模板,但是有的公司会用自己的

-- 点击创建面板里面的空白面板

-- 进入APP的编辑界面 

alt text

-- 现在右边栏选择一个背景,有很多可以选择,也可选择图片 

alt text

-- 右边的侧边栏有对应的图标,可以直接拖进页面 

alt text

-- 然后点击右上角的保存,并在之后输入面板名称,再次点击确认 

alt text

-- 保存好的APP可以在手机上预览,点击右上角的预览,就会生成二维码,用手机上的云智能软件扫描二维码就可以看到APP 

alt text

-- 重新回到刚刚的选择面板就可以选择刚刚设计的面板了 

alt text

 

alt text

-- 剩下的语音交互和产品说明书可以不用管

-- 随后进入设备调试模块,新增测试设备 

alt text

-- 新增的测试设备可以不写,直接点击确认就会自动生成设备名,复制生成的设备名 

alt text

 

alt text

 

alt text

-- 随后回到人机交互,点击产品说明书,然后点击下载配网二维码 

alt text

-- 用云智能APP扫这个码,可能会产生未激活的情况。

-- 那么怎么才能激活呢?需要底层的硬件的连接

-- 云平台操作完成,回归代码


MQTT协议

-- mqtt

-- 先看mqtt协议的相关手册了解mqtt 

alt text

-- 

alt text

alt text

 

alt text

 -- 注意这里0和15的消息类型不用,所以说mqtt协议拥有14中不同的消息类型。

-- mqtt协议专门连接物联网平台

-- 之前咱们连接时间服务器(用tcp连接)

-- 今天去连接阿里云服务器(也是tcp连接)

-- 关键问题是咱们所使用的是物联网平台,是属于阿里云服务器上的一个功能

-- 让数据显示在云平台

--主要是 和云平台建立通信

-- 不同的云平台建立通信的方式是不一样的

-- 阿里云物联网平台自身有自己的通信协议(mqtt协议)

-- 和物联网平台通信,就要用到mqtt协议

-- MQTT 协议的报文格式:固定报头+可变报头+有效载荷

alt text

对于 PUBLISH 来说有效载荷就是应用消息。

-- wifi模块要先建立tcp连接,然后才能用mqtt

-- mqtt到底应该怎么搭建怎么使用

-- 同官方库


-- 将官方库移植到工程

-- MQTT 库移植介绍

  • 1、找到官方库 

    alt text

     

    alt text

  • 2、 

    alt text

  • 3、在工程里面新建文件夹mqtt 

    alt text

  • 4、将源码里面src文件夹里面的文件整体移入mqtt文件里面 

    alt text

  • 5、将mqtt文件添加进工程 

    alt text

  • 6、添加头文件路径 

    alt text

-- 其实咱们用到的函数也就几个:

MQTTSerialize_connect();建立连接报文
MQTTSerialize_publish();建立发布数据报文
MQTTSerialize_subscribe();建立订阅报文
MQTTSerialize_unsubscribe();取消订阅
MQTTSerialize_disconnect();断开连接

-- 应用

-- 官方库怎么用?可以选择百度

-- 用这个连接去实现了功能 Paho mqtt C语言库介绍-CSDN博客

-- 链接讲的是官方库的使用

-- 各个.c文件的作用 

alt text

-- 这里我们根据例程来编写代码,使用官方库

-- 找到例程(可以参考)

alt text

-- 根据mqtt的官方例程,将我们需要用到的部分代码复制进我们的工程。

-- 编写一个mqtt的连接函数

//mqtt的连接函数

void mqtt_connect(void)
{
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//定义了一个结构体,下面对结构体参数赋值
	
	
	data.keepAliveInterval = 60;//保持连接时间(60s)
	data.cleansession = 1;
	data.clientID.cstring = CLIENTID;
	data.username.cstring = USERNAME;
	data.password.cstring = PASSWD;
	
	memset(esp.txbuff,0,1024);
	uint32_t len = MQTTSerialize_connect(esp.txbuff, 1024, &data);//返回值就是txbuff的长度
	//发送连接报文
	uart3_txbuff(esp.txbuff,len);
}

-- 其中,mqtt的ID,用户名和密码,在物联网平台里面可以找到

-- 同时打开物联网平台 

alt text

-- 点击管理控制台 

alt text

-- 点击公共实例,没开通的需要开通 

alt text

-- 点击设备,找到之前我们创建的设备,点击查看 

alt text

-- 找到mqtt的连接参数,点击查看(注意:这些参数是会改变的,随着时间有变化,但是只要连接上一次,以后这些参数就不用再改了)

alt text

-- 点击一键复制 

alt text

-- 将这些参数复制到.h中,然后将他分成5份,可以根据逗号来分 

alt text

-- 将这些参数改为宏定义 

alt text

-- 前三个参数也就是刚刚我们需要的mqtt的ID,用户名和密码

alt text

-- 将AT指令的相关参数更改

-- 今天要通过tcp连接阿里云,所以要改为阿里云的IP的端口,也就是刚刚我们复制的部分参数

alt text

 

alt text

-- 将连接时间服务器改为今天写的mqtt连接函数

alt text

-- 之后打开刚刚的物联网平台,点击我们之前创建的产品,查看 

alt text

-- 选择物模型通信Topic,找到主题,复制主题 

alt text

-- 写成宏定义放在工程的.h中 

alt text

-- 中间的参数是设备名称,将自己的设备名称替代 

alt text

 

alt text

-- 将刚刚定义的宏定义写入发布函数的参数中,还有最后两个参数怎么得到 

alt text

 

alt text

-- 这两个参数是主题名称,负载和负载长度,而负载有固定格式 

alt text

-- 这里也就是buff,其中需要更改的就是以下这些 

alt text

-- 这些名称可以在物联网平台中找到 

alt text

-- 这里先写成定值,注意这里如果后面还有要写的数据,就要写",",否则不写,注意这里格式不能错 

alt text

-- 随后根据官方例程找到mqtt的订阅和发布函数,复制到工程中,更改上述得到的相关参数

void mqtt_pub(void)
{
	//返回值长度
		
	  char buff[512] = {0};
    sprintf(buff,"{\"id\":1724227172076,\"params\":\
                  {\"temperature\":20.1,\
                   \"HCHO\":23,\
                   \"CO2\":23\
                   },\"version\":\"1.0\",\
                   \"method\":\"thing.event.property.post\"}");
	MQTTString topicString = MQTTString_initializer;
  topicString.cstring = TOPIC_PUB;
	memset(esp.txbuff,0,1024);
	uint32_t len = MQTTSerialize_publish(esp.txbuff, 1024, 0, 0, 0, 0,topicString, buff, strlen(buff));	//主题名称,负载和负载长度
	uart3_txbuff(esp.txbuff,len);
}

-- 在主函数中调用

if(rtctime >=999)
		{
			rtctime = 0;
			get_time();
		}
		
		
		if(wifitime >=1000)
		{
			wifitime = 0;
			//天气,时间,ap,云服务器
			wifi_get_time();
		}

-- 更改有封装AT指令的函数

	//要保证能在while循环中运行
uint8_t state = 0;
void wifi_get_time(void)
{

	uint8_t back = 0;
	switch(state)
	{
		case 0:
			back = SendCmdAndJudgeSuccess("AT\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 1:
			back = SendCmdAndJudgeSuccess("AT+RST\r\n","OK",2000);
		if(back == 1)
			state++;
		break;
		case 2:
			back = SendCmdAndJudgeSuccess("AT+CWMODE=1\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 3:
			back = SendCmdAndJudgeSuccess("AT+CIPMUX=0\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 4:
			//在flash里面读取wifi信息esp.wifiname,esp.wifipassword,这里没有用flash,先直接赋值
			strcpy(esp.wifiname,"111"); 
			strcpy(esp.wifipassword,"pimouren"); 
			memset(esp.txbuff,0,1024);
			sprintf(esp.txbuff,"AT+CWJAP=\"%s\",\"%s\"\r\n",esp.wifiname,esp.wifipassword);
			back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
		if(back == 1)
			state++;
		break;
		case 5:
			memset(esp.txbuff,0,1024);
			//sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",TIMEIP,TIMEPORT);	
		//换成阿里云的IP的端口	
		sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",MATTHOSTURL,PORT);
			back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
		if(back == 1)
			state++;
		break;
		case 6:
			back = SendCmdAndJudgeSuccess("AT+CIPMODE=1\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 7:
			back = SendCmdAndJudgeSuccess("AT+CIPSEND\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 8:
//			memset(esp.rxbuff,0,1024);
//			esp.rxlen = 0;
//			esp.rxflag = 0;
//			memset(esp.txbuff,0,1024);
//			sprintf(esp.txbuff,"%s",GETTIME);	
//			uart3_txstr(esp.txbuff);
//			Delay_nms(1000);
//			state++;
		
		mqtt_connect();
		state++;
		break;
		case 9:
			mqtt_pub();
//			if(esp.rxflag==1)
//			{
//				esp.rxflag=0;	
//				uint8_t timebuff[11] = {0};
//				char *p  = strstr((char *)esp.rxbuff,"time");//strstr找到返回地址,没找到返回空
//				if(p!=NULL)
//				{
//					p+=6;
//					
//					for(uint8_t i=0;i<10;i++)
//					{
//						timebuff[i] = *(p+i);
//						
//					}
//				}
//				uint32_t timesec = atoi(timebuff);
//				printf("time:%s		%ld\r\n",timebuff,(long)timesec);
//				updata_time(timesec);
				//state++;
		//	}
			break;
			case 10:
			uart3_txstr("+++");
			Delay_nms(1000);
				state++;
			break;
		case 11:
			back = SendCmdAndJudgeSuccess("AT+CIPCLOSE\r\n","OK",1000);
			if(back == 1)
			state++;
		break;
	}
}

-- 可能会出现的问题:
  • 1、接收的计数值给的单位太小了,而有的AT指令回复的数据量比较大(会回复乱码),导致接收不到数据 ,所以要将单位改大 

    alt text

  • 2、出现上传一遍数据之后程序就不执行了

-- 出现问题先调试,看在哪个位置卡死了,如果出现不明显的错误,就要考虑数组的大小和空间的大小,适当增加数组的大小。

-- 这里出现的问题就是buff的错误,buff的大小不够大,导致接收不到数据,所以将buff的大小改大,就可以正常接收数据了 

alt text

-- 执行效果

-- 执行代码,该设备显示在线,点击该设备,可以看到数据 

alt text

-- 记得点击实时更新 

alt text

-- 设备在线后,就可以用云智能APP扫码查看APP 

alt text

完整代码

  • esp.c
#include "esp.h"
#include "string.h"
#include "delay.h"
#include "rtc.h"
#include "dht11.h"
#include "MQTTPacket.h"
//#include "transport.h"
ESP esp ={0};

void esp_init(void)
{
	//时钟 B端口  USART3(外设自身也有时钟)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);			//看数据手册在哪条线上 - APB2
	
	//IO PA9/PA10
	GPIO_InitTypeDef GPIO_InitStructure = {0};						//定义结构体变量,并且将结构体变量赋初值
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 						//引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//速度
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//PA9 复用推挽
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; 							//引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;		//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //ESP_EN使能引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
	GPIO_Init(GPIOE, &GPIO_InitStructure);
  
	GPIO_SetBits(GPIOE,GPIO_Pin_6);//置1
	
	USART_InitTypeDef USART_InitStructure = {0};
	USART_InitStructure.USART_BaudRate = 115200;   					 			//波特率  常用的是4800 9600  115200
	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_Tx | USART_Mode_Rx;//模式
	USART_Init(USART3, &USART_InitStructure);
	
	USART_Cmd(USART3,ENABLE);//开启串口    //使能或者失能 USART 外设(一般外设都要写这个)
	
	
	//使能中断源			//串口有10个,用哪一个就要开哪一个中断源
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
	
	USART_ITConfig(USART3,USART_IT_IDLE,ENABLE);		//空闲中断怎么开
	
	//中断
	NVIC_InitTypeDef NVIC_InitStructure = {0}; 
	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);
	
}

void USART3_IRQHandler(void)//串口收到1字节数据,中断就会被触发一次
{
	uint8_t data = 0;
	//判断接收中断是否发生
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		//处理中断:保存数据
			data = USART_ReceiveData(USART3);
		USART_SendData(USART1, data);
		
		esp.rxbuff[esp.rxlen++] = data;
		esp.rxlen%=1024;				//计数值最大是1024(前面一堆乱码也会存在buff里面,要控制数据)
		
		//清理终端
		USART_ClearITPendingBit(USART3,USART_IT_RXNE);
	}
	
	
	
	if(USART_GetITStatus(USART3, USART_IT_IDLE) == SET)
	{
		esp.rxflag=1;
		
		//清理空闲中断标志(比较特殊)
		data = USART_ReceiveData(USART3);
		
	}
}

//应用函数

//发送
void uart3_tx(uint8_t data)
{
	while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET){}
	USART_SendData(USART3, data); 
}

void uart3_txbuff(uint8_t *buff,uint32_t len)
{
	for(uint32_t i=0;i<len;i++)
		uart3_tx(buff[i]);
}

//发送不定长数组
void uart3_txstr(uint8_t *buff)
{
	while( *buff )
	{
		uart3_tx(*buff);
		buff++;
	}
}


//判断指令是否发送成功
uint8_t SendCmdAndJudgeSuccess(uint8_t *cmd,uint8_t * ack,uint16_t outtime)//指令和回复的,超时时间(每条指令都有最大的超时时间)
{
	//清空缓冲区
	
	memset(esp.rxbuff,0,1024);
	esp.rxlen = 0;
	esp.rxflag = 0;
	
	
	//1、发送指令
	uart3_txstr(cmd);
	
	//2、判断接收数据中是否有对应的ack
	while(outtime--)
	{
		if(esp.rxflag==1)
		{
			esp.rxflag=0;							//接受两次数据,一次是(前三句话)disconnect会触发,没有OK,然后退出,后面输出ok会再次触发
			if(strstr((char *)esp.rxbuff,(char *)ack)!=NULL)//strstr找到返回地址,没找到返回空
			return 1;
		}
		Delay_nms(1);
	}
	
	return 0;
}
	//要保证能在while循环中运行
uint8_t state = 0;
void wifi_get_time(void)
{

	uint8_t back = 0;
	switch(state)
	{
		case 0:
			back = SendCmdAndJudgeSuccess("AT\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 1:
			back = SendCmdAndJudgeSuccess("AT+RST\r\n","OK",2000);
		if(back == 1)
			state++;
		break;
		case 2:
			back = SendCmdAndJudgeSuccess("AT+CWMODE=1\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 3:
			back = SendCmdAndJudgeSuccess("AT+CIPMUX=0\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 4:
			//在flash里面读取wifi信息esp.wifiname,esp.wifipassword,这里没有用flash,先直接赋值
			strcpy(esp.wifiname,"111"); 
			strcpy(esp.wifipassword,"pimouren"); 
			memset(esp.txbuff,0,1024);
			sprintf(esp.txbuff,"AT+CWJAP=\"%s\",\"%s\"\r\n",esp.wifiname,esp.wifipassword);
			back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
		if(back == 1)
			state++;
		break;
		case 5:
			memset(esp.txbuff,0,1024);
			//sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",TIMEIP,TIMEPORT);	
		//换成阿里云的IP的端口	
		sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",MATTHOSTURL,PORT);
			back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
		if(back == 1)
			state++;
		break;
		case 6:
			back = SendCmdAndJudgeSuccess("AT+CIPMODE=1\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 7:
			back = SendCmdAndJudgeSuccess("AT+CIPSEND\r\n","OK",1000);
		if(back == 1)
			state++;
		break;
		case 8:
//			memset(esp.rxbuff,0,1024);
//			esp.rxlen = 0;
//			esp.rxflag = 0;
//			memset(esp.txbuff,0,1024);
//			sprintf(esp.txbuff,"%s",GETTIME);	
//			uart3_txstr(esp.txbuff);
//			Delay_nms(1000);
//			state++;
		
		mqtt_connect();
		state++;
		break;
		case 9:
			mqtt_pub();
//			if(esp.rxflag==1)
//			{
//				esp.rxflag=0;	
//				uint8_t timebuff[11] = {0};
//				char *p  = strstr((char *)esp.rxbuff,"time");//strstr找到返回地址,没找到返回空
//				if(p!=NULL)
//				{
//					p+=6;
//					
//					for(uint8_t i=0;i<10;i++)
//					{
//						timebuff[i] = *(p+i);
//						
//					}
//				}
//				uint32_t timesec = atoi(timebuff);
//				printf("time:%s		%ld\r\n",timebuff,(long)timesec);
//				updata_time(timesec);
				//state++;
		//	}
			break;
			case 10:
			uart3_txstr("+++");
			Delay_nms(1000);
				state++;
			break;
		case 11:
			back = SendCmdAndJudgeSuccess("AT+CIPCLOSE\r\n","OK",1000);
			if(back == 1)
			state++;
		break;
	}
}

//mqtt的连接函数

void mqtt_connect(void)
{
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//定义了一个结构体,下面对结构体参数赋值
	
	
	data.keepAliveInterval = 60;//保持连接时间(60s)
	data.cleansession = 1;
	data.clientID.cstring = CLIENTID;
	data.username.cstring = USERNAME;
	data.password.cstring = PASSWD;
	
	memset(esp.txbuff,0,1024);
	uint32_t len = MQTTSerialize_connect(esp.txbuff, 1024, &data);//返回值就是txbuff的长度
	//发送连接报文
	uart3_txbuff(esp.txbuff,len);
}

void mqtt_pub(void)
{
	//返回值长度
		
	  char buff[512] = {0};
    sprintf(buff,"{\"id\":1724227172076,\"params\":\
                  {\"temperature\":20.1,\
                   \"HCHO\":23,\
                   \"CO2\":23\
                   },\"version\":\"1.0\",\
                   \"method\":\"thing.event.property.post\"}");
	MQTTString topicString = MQTTString_initializer;
  topicString.cstring = TOPIC_PUB;
	memset(esp.txbuff,0,1024);
	uint32_t len = MQTTSerialize_publish(esp.txbuff, 1024, 0, 0, 0, 0,topicString, buff, strlen(buff));	//主题名称,负载和负载长度
 	uart3_txbuff(esp.txbuff,len);
}



  • esp.h
#ifndef _ESP_H_
#define _ESP_H_

#include "STM32f10x.h"

void esp_init(void);

void USART3_tx(uint8_t data);

void uart3_txbuff(uint8_t *buff,uint32_t len);

void uart3_txstr(uint8_t *buff);

typedef struct {
	uint8_t rxbuff[1024];//接收缓冲区 
	uint16_t rxlen;		//接收计数值
	uint8_t rxflag;
	
	uint8_t txbuff[1024];//发送缓冲区 
	uint8_t txlen;		//发送计数值
	
	uint8_t wifiname[20];
	uint8_t wifipassword[20];
}ESP;
extern ESP esp;

#define TIMEIP "pinduoduo.com"
#define TIMEPORT 80
#define GETTIME "GET http://api.pinduoduo.com/api/server/_stm\r\n"
void wifi_get_time(void);
uint8_t SendCmdAndJudgeSuccess(uint8_t *cmd,uint8_t * ack,uint16_t outtime);

void AP();
void STA();
void mqtt_pub(void);
void mqtt_connect(void);

//前三个参数是mqtt
#define CLIENTID "a11eYOq0ru1.P6WNlYrtAnbisS3rfMEm|securemode=2,signmethod=hmacsha256,timestamp=1729079936092|"
#define USERNAME "P6WNlYrtAnbisS3rfMEm&a11eYOq0ru1"
#define PASSWD  "a4a4e8eec7638bc2c74fc057c5e311051261e38f1a2d1730f32191a475f90011"
#define MATTHOSTURL "a11eYOq0ru1.iot-as-mqtt.cn-shanghai.aliyuncs.com"//阿里云ip地址
#define PORT 1883//端口号

#define TOPIC_PUB "/sys/a11eYOq0ru1/P6WNlYrtAnbisS3rfMEm/thing/event/property/post"

//{"clientId":"a11eYOq0ru1.P6WNlYrtAnbisS3rfMEm|securemode=2,signmethod=hmacsha256,timestamp=1729059510986|",
//	"username":"P6WNlYrtAnbisS3rfMEm&a11eYOq0ru1",
//	"mqttHostUrl":"a11eYOq0ru1.iot-as-mqtt.cn-shanghai.aliyuncs.com",
//"passwd":"a9d11176d0ff901a8e93b3d2cb1eebc64b665f1dda595d1532a4d2ed6a97366c",
//"port":1883}

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2217134.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jeecg3版本的vue,离线启动

jeecg的vue2版本已经停止维护&#xff0c;所以只能用vue3的版本。3版本中使用的是pnpm&#xff08;npm的增强版本&#xff09;下载依赖。使用pnpm安装的node_modules&#xff0c;不能直接复制到离线主机中&#xff08;因为在 pnpm安装过程中&#xff0c;会给依赖的配置文件写死…

qt页面设计

1. Designer 设计师&#xff08;掌握&#xff09; Designer是Qt内置的一款界面设计程序&#xff0c;设计的界面文件为.ui格式。 C程序员通常不会单独启动Designer&#xff0c;如果要在项目中使用Designer程序&#xff0c;只需要在新建项目时&#xff0c;勾选“创建界面文件”选…

基于Springboot+Vue的特殊儿童家长教育能力提升平台 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

《数据结构》课程综合设计(zzu校园导航)(迪杰斯特拉算法)

一、系统&#xff08;问题&#xff09;描述 目前根据郑州大学主校区面积区域的广大&#xff0c;以及南、北核心教学楼的教室分布密集且较多&#xff1b;另外&#xff0c;多数地图软件无法精细导航到一个具体的地点&#xff0c;容易造成原地转圈的烦恼。但是&#xff0c;我们转…

excel 表格中url转图片

待处理的单元格通过如下公式获取目标格式&#xff1a; "<table><img src"&A4&" height20></table>" 然后下拉后获取多列的单元格转换结果&#xff0c; 然后将这些转换后的结果拷贝到纯文本文档中&#xff0c; 然后再将纯文本…

Ubuntu22.04虚拟机安装

一、安装介质下载&#xff1a; 在官网下载安装镜像&#xff0c;下载地址https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso 二、操作系统安装&#xff1a; step 1:进入ubuntu的安装界面&#xff0c;直接回车安装。 step 2:选择语言&#xff0c;直接回…

pycharm 找不到conda环境

参考&#xff1a;新版Pycharm解决Conda executable is not found-CSDN博客

软件界面设计深度解析:流程、工具与用户体验

1、什么是软件界面 软件界面设计是指对软件的外观和用户体验进行美化、优化和标准化的过程。这包括软件的启动封面、框架、菜单、标签、安装过程、滚动条、状态栏、面板、图标设计&#xff0c;以及软件的包装和商业化设计。简单来说&#xff0c;我们日常使用微信时所看到的聊天…

天锐绿盾VS Ping32数据安全新选择,用户体验分享

随着网络威胁日益严重&#xff0c;如何保护个人和企业的网络安全成为了一个迫在眉睫的问题。天锐绿盾和Ping32作为市场上两款备受欢迎的网络安全软件&#xff0c;各自拥有独特的特点和功能。本文将对这两款软件进行深入的使用体验分享&#xff0c;帮助用户做出最佳选择。 防护性…

C++ 11 的 codecvt 与编码转换

1 编码与乱码 乱码产生的主要原因是编码与字符集不匹配&#xff0c;这种不匹配时怎么造成的呢&#xff1f;首先要来了解一下编码和字符集的关系。 1.1 编码与字符集 由于标准的英文 ASCII 已经成了全球标准&#xff0c;每台电脑的 BIOS 里存着一份标准 ASCII 表&#xff08;…

ES6扩展运算符

1.介绍&#xff1a; ... 扩展运算符能将数组转换为逗号分隔的参数序列&#xff1b; 扩展运算符&#xff08;spread&#xff09;也是三个点&#xff08;...&#xff09;。它好比 rest 参数的逆运算&#xff0c;将一个数组转为用逗号分隔的 参数序列&#xff0c;对数组进…

IP数据包格式、ICMP封装步骤

IP数据包格式 版本号&#xff1a;占4位&#xff0c;表示IP协议的版本&#xff0c;目前广泛使用的是IPv4&#xff0c;其版本号为4。 首部长度&#xff1a;占4位&#xff0c;表示IP首部的长度&#xff0c;单位为32位字节。首部长度最小为20字节&#xff0c;最大为60字节。 服务…

2.Java--入门程序

一、开发Java程序 步骤&#xff1a; 1.编写代码 其中第一行的HelloWorld叫类名&#xff0c;下面的框架叫main()方法&#xff0c; 类名要和文件名一致&#xff0c; 2.编译代码 用Javac进行编译&#xff0c;将编写的代码保存之后&#xff0c;打开WindowsR输入cmd 用cd文件夹…

40系显卡配置Apollo9.0

文章目录 一、下载安装 Apollo 源码1. 克隆 Apollo 源码 二、 启动Apollo环境容器三、 进入Apollo环境四、编译五、启动 Apollo 进行播包验证5.1 获取数据包5.2 启动 Dreamview5.3 在 Dreamview 中播放数据包5.4 通过命令行播放数据包 宿主机基础环境 系统&#xff1a;ubuntu22…

关键词提取技术:TextRank 详解

1. 什么是 TextRank&#xff1f; TextRank 是一种基于图的排序算法&#xff0c;用于从文本中提取关键词和进行自动摘要。它是受 Google 的 PageRank 算法启发而提出的。与 TF-IDF 不同&#xff0c;TextRank 不依赖外部语料库&#xff0c;也不需要训练数据。它通过构建词语之间的…

JavaWeb合集06-MySQL数据库

六、MySQL数据库 关系型数据库(RDBMS)&#xff1a;建立在关系模型基础上&#xff0c;由多张相互连接的二维表组成的数据库。 特点&#xff1a; 使用表存储数据&#xff0c;格式统一, 便于维护. 使用SQL语言操作&#xff0c;标准统一&#xff0c;使用方便&#xff0c;可用于复杂…

js中map,filter,find,foreach的用法介绍

js中map&#xff0c;filter&#xff0c;find&#xff0c;foreach的用法介绍 在 JavaScript 中&#xff0c;数组提供了一些常用的迭代方法&#xff0c;如 map、filter、find 和 forEach&#xff0c;这些方法允许你对数组中的每个元素进行操作&#xff0c;下面是它们的用法和区别…

用示波器观测RC一阶电路零输入响应是否激励必须是方波信号

概述 RC一阶电路是一种简单但非常重要的电路&#xff0c;广泛应用于滤波、信号处理和时间常数分析等领域。在研究RC电路的动态特性时&#xff0c;零输入响应&#xff08;Natural Response&#xff09;是一项关键内容。本文将详细解析用示波器观测RC一阶电路零输入响应时&#…

基于 MyBatis Plus 分页封装分页方法

一、前言 作为一个 CRUD 工程师&#xff0c;查询必然少不了&#xff0c;分页查询更是常见&#xff0c;市面上也有很多成熟的分页插件&#xff0c;都各有优缺点&#xff0c;这里整理一下&#xff0c;基于 MybatisPlus 的分页插件进一步封装分页的公共方法。 二、对象封装 其实…

elementUI,设置日期,只能选择过去的和今天的日期

在 el-date-picker 组件中加&#xff1a;:picker-options"pickerOptions" <el-form-item label"票据生成日期&#xff1a;"> <el-date-picker v-model"date1" type"daterange" range-separator"至" value-format&…