本文所需硬件:STM32F103C8T6、LED、ESP01s、DHT11、面包板、杜邦线,实现功能:温湿度上传和远程开关灯的基本功能。使用的是AT指令MQTT版本固件的ESP01s,基于此固件版本进行说明。
其他说明(本文主要介绍代码的实现,具体全过程会给附上视频链接)
onenet云平台的创建和AT固件烧录的详细内容请看这个视频⬇⬇⬇⬇⬇⬇
记录onenet平台 mqtt产品和设备信息_哔哩哔哩_bilibili
DHT11驱动代码参考⬇⬇⬇⬇⬇⬇
【STM32】驱动DHT11(CubeMX配置)(HAL库)_dht11驱动代码-优快云博客
成果演示
智能家居
主要的AT指令
AT指令(Attention Command)是一种基于文本的交互协议,用于通过串口(如UART)控制模块执行特定操作(如连接Wi-Fi、发送数据等)。它是模块与主控设备(如MCU、PC)通信的桥梁,具有简单、通用的特点。
AT
意义:这个指令是用来测试串口通信是否畅通的最基本指令。发送AT应该返回OK,代表通信没有问题。
作用:验证ESP8266-01s模块已经正确连接并且准备接收更多的AT指令。
AT+CWMODE=1
意义:该指令用于设置ESP8266的Wi-Fi工作模式。CWMODE=1将模块设置为Station模式(STA模式),这意味着模块可以连到一个已存在的Wi-Fi网络。
作用:配置ESP8266作为Wi-Fi客户端,让其可以连接到无线路由器。
AT+CWDHCP=1,1
意义:此指令用于设置DHCP(动态主机配置协议)。CWDHCP=1,1的设置使ESP8266在Station模式下启用DHCP客户端,这样它可以自动从网络路由器获取IP地址。
作用:确保ESP8266在连接到Wi-Fi网络时能够自动获得IP地址。
AT+CWJAP="wifi名称","wifi密码"
意义:此指令用于连接到一个Wi-Fi热点。
作用:使ESP8266连接到指定的Wi-Fi热点。
AT+MQTTUSERCFG=0,1,"设备名称","产品ID","token",0,0,""
意义:这个指令用于配置MQTT客户端的用户参数。参数0指的是客户端ID,1为MQTT版本,最后的两个0表示是否清理会话和是否启用遗嘱消息。
作用:设置了客户端的认证信息和其他MQTT连接选项,这对于与MQTT代理进行通信是必要的。
AT+MQTTCONN=0,"mqtts.heclouds.com",1883,1
意义:此指令用于发起到MQTT服务器的连接。参数0是客户端ID,"mqtts.heclouds.com"是MQTT服务器地址,1883是服务器端口号,最后的1表示启用清理会话。
作用:根据提供的服务器详情和客户端配置信息,指令会尝试建立MQTT连接。
AT+MQTTSUB=0,"$sys/产品ID/设备名称/thing/property/post/reply",0
意义:指令用于订阅MQTT主题。0是客户端ID,中间的内容是是MQTT主题,最后的0是请求的服务质量(QoS)等级。
作用:向MQTT服务器表明客户端想要接收与该主题相关的消息。
AT+MQTTPUB=0,"$sys/产品ID/设备名称/thing/property/post","{\"id\":\"123\"\,\"params\":{\"temp\":{\"value\":23.6\}}}",0,0
意义:通过此指令将消息发布到MQTT主题。0是客户端ID,"$sys/产品ID/设备名称/thing/property/post"是要发布消息的主题。紧接着的是要发布的消息内容,temp是你设置的变量名,23.6是发送数值,0,0分别表示消息的QoS等级和是否保留消息。
作用:发送一条消息到MQTT服务器,服务器则将该消息转发给订阅了对应主题的所有客户端。
AT+MQTTSUB=0,"$sys/产品ID/设备名称/thing/property/set",0
意义:该指令用于指示ESP8266模块订阅一个指定的MQTT主题。
作用:使ESP8266模块能够监听并接收到任何发送到这个主题的消息,通常这些消息是针对设备设置或控制指令。
依次发送以上AT指令就可以实现esp8266连接onenet云平台,可以先使用串口助手测试一下能不能正常的连接(如果不可以,仔细检查一下配置,有的AT指令很长,容易出错),如果可以正常连接再进行下一步,使用stm32连接esp8266上传云端数据。
cubemx的配置
主要就是打开串口1(调试串口)、串口2(发送AT指令)、定时器(每隔一段时间上传一次数据,降低功耗)、配置DHT11的GPIO引脚和控制led灯的GPIO引脚。还有一些基本配置我就不多说了(开启时钟、配置时钟树、debug设置)。
接线图
这里最好用一个稳压模块,因为esp01s模块对电压要求特别高,刚开始博主因为没有稳压模块,一直找不出错误,很恼火。还有就是esp01s和stm32的TX和RX引脚别接错,一定是RX接TX。
代码部分
主函数
主函数很简单,就是查看各种标志位,做出响应。
还有一些cubemx自动生成的初始化配置我没有列出来,只要配置没问题就肯定没问题。
ONENET_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//定时器设置时间到,设置标志位,向云端传输数据
if(ledflag==1){
DHT_Read(); //获取温湿度
ledflag =0; //标志位清零
cntnum=Data[0]; //获取湿度值
ESP_Senddata("S",cntnum);//发送湿度数据
//必须延时,不然第一次数据发完没接收到响应,直接再次发送会发送失败
HAL_Delay(80);
cntnum=Data[2]; //获取温度值
ESP_Senddata("T",cntnum);//发送温度数据
}
//接收led亮数据后,发送led灭给云端
if(ledflag2==1){
ledflag2=0;
sprintf(cmdcmd,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"led\\\":{\\\"value\\\":true\\}}}\",0,0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdcmd);
}
//接收led灭数据后,发送led灭给云端
if(ledflag3==1){
ledflag3=0;
sprintf(cmdcmd,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"led\\\":{\\\"value\\\":false\\}}}\",0,0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdcmd);
}
}
串口发送数据函数(主要是发送AT指令)
void ESP8266_SendCmd(const char* command) {
HAL_UART_Transmit(&huart2, (uint8_t*)command, strlen(command), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
发送AT指令连接onenet云平台,AT指令具体作用上面有讲解,这里不再解释
这里有一些宏定义:WIFI_SSID->wifi名称,WIFI_PASSWD->wifi密码,
MQTT_ID->产品ID,MQTT_NAME->设备名称,MQTT_TOKEN->你的token值。
void ONENET_Init(void){
//初始化时获取一次温湿度
DHT_Read();
//等待esp8266上电稳定
HAL_Delay(1000);
char cmdBuf[256];
ESP8266_SendCmd("AT+RST");
HAL_Delay(2000);
ESP8266_SendCmd("AT");
HAL_Delay(1000);
ESP8266_SendCmd("AT+CWMODE=1");
HAL_Delay(2000);
sprintf(cmdBuf,"AT+CWDHCP=1,1");
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+CWJAP=\"%s\",\"%s\"",WIFI_SSID,WIFI_PASSWD);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(4000);
sprintf(cmdBuf, "AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"", MQTT_NAME, MQTT_ID, MQTT_TOKEN);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf, "AT+MQTTCONN=0,\"mqtts.heclouds.com\",1883,1");
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+MQTTSUB=0,\"$sys/%s/%s/thing/property/post/reply\",0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+MQTTSUB=0,\"$sys/%s/%s/thing/property/set\",0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"led\\\":{\\\"value\\\":false\\}}}\",0,0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdBuf);
//开启数据接收中断
HAL_UART_Receive_IT(&huart2, &uart_rx_data, 1);
//开启定时器中断 一定要在连接完云平台之后再开启
HAL_TIM_Base_Start_IT(&htim2);
}
向云平台发送数据函数,需要传入变量名和数值(变量名必须和云平台上设置的一致)
void ESP_Senddata(const char *name,const char cnt){
char cmd[256];
sprintf(cmd,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0",MQTT_ID,MQTT_NAME,name,cnt);
ESP8266_SendCmd(cmd);
}
定时器中断回调函数,主要设置标志位,不能在中断里运行太长时间
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
ledflag=1;
}
}
串口接收函数,主要是接收云端发来的数据和指令,做出响应,并且给出回应,接收数据成功。
这里没有使用json库处理数据,因为我还不会。(求教)
void HandleCloudMsg(char *msg) {
char req_id[32] = {0};
char *id_start = strstr(msg, "\"id\":\"");
if(id_start) {
id_start += 6; // 跳过"id\":\""
char *id_end = strchr(id_start, '"');
if(id_end) {
int id_len = id_end - id_start;
strncpy(req_id, id_start, id_len);
req_id[id_len] = '\0';
}
}
// 查找关键字段(避免使用复杂库)
char *led_pos = strstr(msg, "\"led\":");
if(led_pos != NULL) {
// 提取状态值
char state = *(led_pos + 6); // 冒号后的第一个字符
if(state == 't') { // true
led1_ON(); //自己写的控制led亮灭的函数,这个都会吧
MQTT_SendResponse(req_id);
ledflag2=1;
} else if(state == 'f') { // false
led1_OFF(); //自己写的控制led亮灭的函数,这个都会吧
MQTT_SendResponse(req_id);
ledflag3=1;
}
}
}
// 发送指令响应到云平台
void MQTT_SendResponse(char* request_id) {
// 构造响应JSON
char response_json[128];
sprintf(response_json,
"{\\\"id\\\":\\\"%s\\\"\\,\\\"code\\\":200\\,\\\"msg\\\":\\\"success\\\"}",
request_id);
// 发布到响应主题
char topic[128];
sprintf(topic, "$sys/%s/%s/thing/property/set_reply",
MQTT_ID, MQTT_NAME);
// 发送MQTT消息
char mqtt_send_buf[256];
sprintf(mqtt_send_buf, "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n",
topic, response_json);
ESP8266_SendCmd(mqtt_send_buf);
}
// 串口接收完成中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART2) { // 来自ESP模块的数据
// 保存接收到的字节
msg_buf[msg_len++] = uart_rx_data;
// 检测消息结束(根据实际情况调整)
if(uart_rx_data == '}' || msg_len >= sizeof(msg_buf)-1) {
msg_buf[msg_len] = '\0'; // 添加字符串结束符
// 检测是否为控制消息
if(strstr(msg_buf, "thing/property/set")) {
HandleCloudMsg(msg_buf); // 处理消息
}
msg_len = 0; // 重置缓冲区
}
// 重新启用接收中断
HAL_UART_Receive_IT(&huart2, &uart_rx_data, 1);
}
}
完整代码
esp8266代码
//esp8266.h文件
#ifndef __ESP8266_H
#define __ESP8266_H
#include "head.h"
//这些宏定义更换成自己的
#define WIFI_SSID "wifi名称"
#define WIFI_PASSWD "wifi密码"
#define MQTT_ID "产品id"
#define MQTT_NAME "设备名称"
#define MQTT_TOKEN "token值"
void ESP8266_SendCmd(const char* command);
void ONENET_Init(void);
void HandleCloudMsg(char *msg);
// 添加在文件末尾
void MQTT_SendResponse(char* request_id);
#endif
//esp8266.c文件
#include "head.h"
char ledflag=0;
char ledflag2=0;
char ledflag3=0;
extern UART_HandleTypeDef huart2; // 声明外部串口
uint8_t uart_rx_data; // 串口接收缓存
char msg_buf[256]; // 消息缓冲区
uint16_t msg_len = 0; // 当前消息长度
void ESP8266_SendCmd(const char* command) {
HAL_UART_Transmit(&huart2, (uint8_t*)command, strlen(command), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
void ONENET_Init(void){
//初始化时获取一次温湿度
DHT_Read();
//等待esp8266上电稳定
HAL_Delay(1000);
char cmdBuf[256];
ESP8266_SendCmd("AT+RST");
HAL_Delay(2000);
ESP8266_SendCmd("AT");
HAL_Delay(1000);
ESP8266_SendCmd("AT+CWMODE=1");
HAL_Delay(2000);
sprintf(cmdBuf,"AT+CWDHCP=1,1");
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+CWJAP=\"%s\",\"%s\"",WIFI_SSID,WIFI_PASSWD);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(4000);
sprintf(cmdBuf, "AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"", MQTT_NAME, MQTT_ID, MQTT_TOKEN);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf, "AT+MQTTCONN=0,\"mqtts.heclouds.com\",1883,1");
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+MQTTSUB=0,\"$sys/%s/%s/thing/property/post/reply\",0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+MQTTSUB=0,\"$sys/%s/%s/thing/property/set\",0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdBuf);
HAL_Delay(2000);
sprintf(cmdBuf,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"led\\\":{\\\"value\\\":false\\}}}\",0,0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdBuf);
//开启数据接收中断
HAL_UART_Receive_IT(&huart2, &uart_rx_data, 1);
//开启定时器中断 一定要在连接完云平台之后再开启
HAL_TIM_Base_Start_IT(&htim2);
}
void ESP_Senddata(const char *name,const char cnt){
char cmd[256];
sprintf(cmd,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0",MQTT_ID,MQTT_NAME,name,cnt);
ESP8266_SendCmd(cmd);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
ledflag=1;
}
}
void HandleCloudMsg(char *msg) {
char req_id[32] = {0};
char *id_start = strstr(msg, "\"id\":\"");
if(id_start) {
id_start += 6; // 跳过"id\":\""
char *id_end = strchr(id_start, '"');
if(id_end) {
int id_len = id_end - id_start;
strncpy(req_id, id_start, id_len);
req_id[id_len] = '\0';
}
}
// 查找关键字段(避免使用复杂库)
char *led_pos = strstr(msg, "\"led\":");
if(led_pos != NULL) {
// 提取状态值
char state = *(led_pos + 6); // 冒号后的第一个字符
if(state == 't') { // true
led1_ON();
MQTT_SendResponse(req_id);
ledflag2=1;
} else if(state == 'f') { // false
led1_OFF();
MQTT_SendResponse(req_id);
ledflag3=1;
}
}
}
// 发送指令响应到云平台
void MQTT_SendResponse(char* request_id) {
// 构造响应JSON
char response_json[128];
sprintf(response_json,
"{\\\"id\\\":\\\"%s\\\"\\,\\\"code\\\":200\\,\\\"msg\\\":\\\"success\\\"}",
request_id);
// 发布到响应主题
char topic[128];
sprintf(topic, "$sys/%s/%s/thing/property/set_reply",
MQTT_ID, MQTT_NAME);
// 发送MQTT消息
char mqtt_send_buf[256];
sprintf(mqtt_send_buf, "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n",
topic, response_json);
ESP8266_SendCmd(mqtt_send_buf);
}
// 串口接收完成中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART2) { // 来自ESP模块的数据
// 保存接收到的字节
msg_buf[msg_len++] = uart_rx_data;
// 检测消息结束(根据实际情况调整)
if(uart_rx_data == '}' || msg_len >= sizeof(msg_buf)-1) {
msg_buf[msg_len] = '\0'; // 添加字符串结束符
// 检测是否为控制消息
if(strstr(msg_buf, "thing/property/set")) {
HandleCloudMsg(msg_buf); // 处理消息
}
msg_len = 0; // 重置缓冲区
}
// 重新启用接收中断
HAL_UART_Receive_IT(&huart2, &uart_rx_data, 1);
}
}
DHT11代码(包含需要的微秒级延时函数)
这里是移植的开头那位大佬的代码。
//delay.h文件
#ifndef DELAY_DELAY_H_
#define DELAY_DELAY_H_
#include "head.h"
void Delay_us(uint32_t us);
#endif
//delay.c文件
#include "head.h"
#define LOOPS_PER_US 9 // 72MHz下典型值
void Delay_us(uint32_t us)
{
uint32_t count = us * LOOPS_PER_US;
while(count--);
}
//DHT11.h文件
#ifndef __DHT11_H
#define __DHT11_H
#include "head.h"
void DHT_GPIO_SET_OUTPUT(void);
void DHT_GPIO_SET_INPUT(void);
uint8_t DHT_Read_Byte(void);
uint8_t DHT_Read(void);
#endif
//DHT11.c
#include "head.h"
uint8_t Data[5]={0x00,0x00,0x00,0x00,0x00}; //Data存储读取的温湿度信息
/*------------------------------*/
void DHT_GPIO_SET_OUTPUT(void) //设置GPIOx为输出模式(MCU的IO口向DHT11发激活信号)
{
GPIO_InitTypeDef GPIO_InitStructure; //在GPIO_InitTypeDef结构体中修改IO口参数(结构体成员)
GPIO_InitStructure.Pin=DHT11_DA_Pin; //设置的格式必须严格遵循注释,比如GPIO_PIN_define
GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void DHT_GPIO_SET_INPUT(void) //设置GPIOx为输入模式(DHT11向MUC的IO发电平信号,信号里包含了温湿度信息)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin=DHT11_DA_Pin;
GPIO_InitStructure.Mode=GPIO_MODE_INPUT;
GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}
/*------------------------------*/
/*
uint8_t DHT_Read_Byte(void)用于转译采集DHT11发送给IO口的电平信号(8位)。
*/
uint8_t DHT_Read_Byte(void) //从DHT11读取一位(8字节)信号
{
uint8_t ReadData=0; //ReadData用于存放8bit数据,即8个单次读取的1bit数据的组合
uint8_t temp; //临时存放信号电平(0或1)
uint8_t retry=0; //retry用于防止卡死
uint8_t i;
for(i=0; i<8; i++) //一次温湿度信号读取八位
{
while(HAL_GPIO_ReadPin(GPIOA,DHT11_DA_Pin)==0 && retry<100)
//等待直到DHT11输出高电平:当PA5=1,上升沿,表示开始接受数据,可以判断0 or 1,跳出循环,执行后续判断(若PA5=0,将一直循环等待)
{
Delay_us(1);
retry++; //retry防止PA5读取不到数据卡死在这一步,当经历100us后retry自增到100,跳出循环。
}
retry=0;
Delay_us(40); //延时30us
//根据时序图,DHT传回高电平信号维持26us~28us表示0, 维持70us表示1
//延时30us后,如果IO读取到仍是高电平,说明采集到1;如果IO读取到低电平,说明采集到0
//读取电平信号暂存temp内,随后会压入ReadData中
if(HAL_GPIO_ReadPin(GPIOA,DHT11_DA_Pin)==1) temp=1;
else temp=0;
while(HAL_GPIO_ReadPin(GPIOA,DHT11_DA_Pin)==1 && retry<100)
//等待直到DHT11输出低电平,表示退出。本轮1bit信号接收完毕。
{
Delay_us(1);
retry++;
}
retry=0;
ReadData<<=1; //ReadData内信号先全部左移一位,空出末尾位置
ReadData |= temp; //将temp写入ReadData
}
return ReadData;
}
/*------------------------------*/
/*
uint8_t DHT_Read(void)表达完整时序
*/
uint8_t DHT_Read(void)
{
uint8_t retry=0;
uint8_t i;
DHT_GPIO_SET_OUTPUT(); //IO设置为输出模式。在传输的最开始,MCU要向DHT11发送信号
HAL_GPIO_WritePin(GPIOA,DHT11_DA_Pin,GPIO_PIN_RESET); //IO->DHT11:先拉低电平18ms(应时序要求)
HAL_Delay(18);
HAL_GPIO_WritePin(GPIOA,DHT11_DA_Pin,GPIO_PIN_SET); //IO->DHT11:随后拉高电平20us
Delay_us(20);
//MCU通过IO向DHT11发送请求完毕。接下来DHT11向IO发送响应,IO转为输入模式。在这之后就开始信号的转译读取。
DHT_GPIO_SET_INPUT();
Delay_us(20);
if(HAL_GPIO_ReadPin(GPIOA,DHT11_DA_Pin)==0) //DHT11发回低电平响应(读取到低电平,说明DHT11有响应)
{
//接下来,DHT11拉低电平一段时间后拉高电平一段时间
while(HAL_GPIO_ReadPin(GPIOA,DHT11_DA_Pin)==0 && retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
while(HAL_GPIO_ReadPin(GPIOA,DHT11_DA_Pin)==1 && retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
//一共传输40位,一次DHT_Read_Byte返回8位,共读取5次。存储在Data[]中。(Data[]定义为全局)
for(i=0; i<5; i++)
{
Data[i] = DHT_Read_Byte(); //每次读取一字节(8位)
}
Delay_us(50);
//说明:Data[0]湿度, Data[2]温度。Data[1]和Data[3]分别为湿度和温度的小数位。Data[4]用于校验。
}
uint32_t sum=Data[0]+Data[1]+Data[2]+Data[3]; //校验
if((sum)==Data[4]) return 1;
else return 0;
}
主函数
里面有一些cubemx配置自动生成的代码部分我没有列出来,我只列出来了主要部分
extern char ledflag;
extern char ledflag2;
extern char ledflag3;
extern uint8_t Data[5];
char cmdcmd[256];
char cntnum=0;
int main(void)
{
while(1){
if(ledflag==1){
DHT_Read(); //获取温湿度
ledflag =0; //标志位清零
cntnum=Data[0]; //获取湿度值
ESP_Senddata("S",cntnum);//发送湿度数据
//必须延时,不然第一次数据发完没接收到响应,直接再次发送会发送失败
HAL_Delay(80);
cntnum=Data[2]; //获取温度值
ESP_Senddata("T",cntnum);//发送温度数据
}
//接收led亮数据后,发送led灭给云端
if(ledflag2==1){
ledflag2=0;
sprintf(cmdcmd,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"led\\\":{\\\"value\\\":true\\}}}\",0,0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdcmd);
}
//接收led灭数据后,发送led灭给云端
if(ledflag3==1){
ledflag3=0;
sprintf(cmdcmd,"AT+MQTTPUB=0,\"$sys/%s/%s/thing/property/post\",\" {\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"led\\\": {\\\"value\\\":false\\}}}\",0,0",MQTT_ID,MQTT_NAME);
ESP8266_SendCmd(cmdcmd);
}
}
}
总结
以上代码,只能实现基本的数据上传和数据处理,如果需要更复杂的场景,还需要更多的优化,欢迎大家提出建议和优化方案。