基于 STM32F103 + ESP8266 实现 DHT11 温湿度数据上传华为云 IoT 平台

📅 发布时间:2026/7/16 6:46:11 👁️ 浏览次数:
基于 STM32F103 + ESP8266 实现 DHT11 温湿度数据上传华为云 IoT 平台
文章目录基于 STM32F103 ESP8266 实现 DHT11 温湿度数据上传华为云 IoT 平台项目架构概览准备工作硬件连接软件依赖华为云 IoT 设备配置工作流程STM32向ESP8266发送AT指令连接WIFISTM32向ESP8266发送AT指令连接华为云平台STM32控制ESP8266发送AT指令向云平台发送数据主函数效果展示基于 STM32F103 ESP8266 实现 DHT11 温湿度数据上传华为云 IoT 平台在物联网项目中将本地传感器数据上传至云端是核心需求之一。本文将手把手教你如何使用STM32F103C8T6驱动 ESP8266 模块通过AT 指令连接华为云 IoT 平台并将DHT11 采集的温湿度数据以 JSON 格式上报。代码仓库项目架构概览[DHT11]→[STM32F103]←→[ESP8266(AT 指令)]→ 华为云 IoT ↑ ↑(单总线通信)(USART2通信)主控STM32F103C8T6WiFi 模块ESP8266固件支持 MQTT AT 指令传感器DHT11单总线温湿度云平台华为云 IoTDA设备接入服务准备工作硬件连接STM32ESP8266PA2 (USART2_TX)RXPA3 (USART2_RX)TX3.3VVCC、CH_PDGNDGND注STM32的USART1与电脑的串口模块连接用来打印调试信息PA9 – RXD软件依赖STM32 标准外设库自定义Delay.h基于 SysTick已实现 DHT11 驱动华为云 IoT 设备信息需提前在控制台创建华为云 IoT 设备配置在 华为云 IoT 控制台 创建设备后获取以下信息/* 连接您的WIFI SSID和密码 */#defineWIFI_SSIDyour_wifi_ssid#defineWIFI_PASSWDyour_wifi_password#defineDEVICEIDyour_decice_id#defineDECIVESECRETyour_decice_secert/* 线上环境域名和端口号不需要改 */#defineMQTT_SERVERc80c8bf1c5.st1.iotda-device.cn-north-4.myhuaweicloud.com#defineMQTT_PORT1883#defineMQTT_USRNAMEyour_mqtt_username// 硬件的ID和密码#defineMQTT_CLIENT_IDyour_mqtt_client_id#defineMQTT_PASSWDyour_mqtt_password工作流程由于STM32向ESP8266发送AT指令这一步骤会被多次使用因此我们将该功能封装为一个函数/** * brief 向 ESP8266 发送 AT 指令并等待期望响应 * param cmd: 要发送的 AT 指令字符串必须以 \r\n 结尾 * param response: 期望在 ESP8266 返回数据中出现的关键字如 OK, WIFI CONNECTED * param timeout: 超时时间单位10ms总等待时间 ≈ timeout × 10ms * retval 0: 在超时前收到包含 response 的响应操作成功 * retval 1: 超时未收到期望响应操作失败 * * note 该函数依赖全局变量 * - WiFi_RxBufferESP8266 串口接收缓冲区由 USART1 中断或轮询填充 * - flag特殊延时标志用于某些耗时较长的指令如 MQTT 连接 */u8ESP8266_SendAT(char*cmd,char*response,u16 timeout){// 1. 清空上一次的接收缓冲区避免残留数据干扰判断USART1_ClearBuffer();// 2. 发送 AT 指令到 ESP8266通过 USART1USART1_SendString(cmd);// 3. 等待 1 秒确保 ESP8266 有足够时间开始处理指令并返回初步响应// 某些指令如 ATRST、ATCWJAP 响应较慢Delay_ms(1000);// 4. 【特殊处理】检查全局标志位 flag// 若 flag 1说明当前指令可能需要额外延时如首次 MQTT 连接// 此处清零 flag 并追加 3 秒延时防止因响应延迟导致误判超时if(flag){flag0;// 清除标志避免重复触发Delay_ms(3000);// 额外等待 3 秒适用于 MQTTCONN 等慢响应指令}// 5. 循环等待期望响应最多等待 timeout × 10mswhile(timeout--){// 检查接收缓冲区是否包含期望的关键字如 OKif(strstr(WiFi_RxBuffer,response)){return0;// 找到响应立即返回成功}Delay_ms(10);// 每次循环间隔 10ms降低 CPU 占用}// 6. 超时仍未收到期望响应返回失败return1;}STM32向ESP8266发送AT指令连接WIFISTM32向ESP8266发送AT指令连接WIFI的具体步骤如下格式化ESP8266进行基本响应测试配置Station模式取消自动连接连接WiFi连接前两步是为了保证ESP8266能正常工作确保出bug后不是ESP8266的问题ESP8266 支持以下三种 WiFi 工作模式通过ATCWMODE设置模式值功能类比Station (STA)1作为客户端连接到外部 WiFi 路由器≈ 手机、笔记本连 WiFiSoftAP2作为热点其他设备可连接它≈ 手机开热点Station SoftAP3同时具备以上两种功能≈ 路由器既连上级网络又发热点因此只有 Station 模式下的 ESP8266 才能作为“客户端”去连接外部的 WiFi 路由器AP/** * brief 初始化 ESP8266 并连接到指定的 WiFi 路由器 * note 执行流程 * 1. 恢复出厂设置可选确保干净状态 * 2. 测试基础 AT 通信 * 3. 设置为 Station 模式必须 * 4. 关闭自动连接避免干扰 * 5. 连接目标 WiFi 网络 * retval 0: 初始化并连接成功 * retval 1: 基础通信或恢复失败 * retval 2: 模式配置失败 * retval 3: WiFi 连接失败 */u8ESP8266_InitWiFi(void){// 1. 【可选】恢复出厂设置// 清除所有保存的配置如 SSID、密码、MQTT 设置等确保从干净状态开始// 避免因历史配置冲突导致连接异常if(ESP8266_SendAT(ATRESTORE\r\n,OK,1000)){printf(%s\r\n,WiFi_RxBuffer);// 打印实际返回内容便于调试printf(格式化异常\r\n);return1;}printf(格式化成功\r\n);// 2. 发送最简单的 AT 指令测试 STM32 与 ESP8266 串口通信是否正常// 正常响应应为\r\nOK\r\nif(ESP8266_SendAT(AT\r\n,OK,1000)){printf(基本响应测试异常\r\n);return1;}printf(基本响应测试成功\r\n);// 3. 【关键步骤】配置 ESP8266 为 Station 模式模式 1// 只有在此模式下ESP8266 才能作为客户端连接外部 WiFi 路由器// 若跳过此步后续 ATCWJAP 将失败if(ESP8266_SendAT(ATCWMODE1\r\n,OK,1000)){printf(配置Station模式失败\r\n);return2;}printf(配置Station模式成功\r\n);// 4. 关闭上电自动连接功能// ATCWAUTOCONN0禁止 ESP8266 启动时自动连接上次保存的 WiFi// 原因我们希望由主控STM32完全控制连接逻辑避免自动连接旧网络if(ESP8266_SendAT(ATCWAUTOCONN0\r\n,OK,1000)){printf(取消自动连接失败\r\n);return2;}printf(取消自动连接成功\r\n);// 5. 构造连接 WiFi 的 AT 指令// 格式ATCWJAPSSID,PASSWORD// 注意SSID 和密码中的特殊字符需转义本例假设无特殊字符charconnectWiFiCmd[64];sprintf(connectWiFiCmd,ATCWJAP\%s\,\%s\\r\n,WIFI_SSID,WIFI_PASSWD);// 6. 发送连接指令并等待关键响应 WIFI CONNECTED// ⚠️ 注意此处的成功标志是 WIFI CONNECTED不是 OK// 因为 OK 可能在连接完成前就返回而 WIFI CONNECTED 表示真正连上路由器if(ESP8266_SendAT(connectWiFiCmd,WIFI CONNECTED,5000)){printf(WiFi连接失败\r\n);return3;}printf(WiFi连接成功\r\n);// 7. 返回成功return0;}STM32向ESP8266发送AT指令连接华为云平台/** * brief 配置并连接 ESP8266 到华为云 IoT 平台MQTT 协议 * note 华为云设备接入要求 * - 使用平台分配的 ClientID、Username、Password * - 连接地址c80c8bf1c5.st1.iotda-device.cn-north-4.myhuaweicloud.com * - 端口1883非加密因普通 ESP8266 不支持 TLS * retval 0: 连接成功 * retval 1: MQTT 参数配置失败 * retval 2: MQTT 连接失败 */u8ESP8266_ConnectHuaweiCloud(void){// 1. 构造 MQTT 用户配置指令ATMQTTUSERCFG// 格式ATMQTTUSERCFGlinkID,scheme,client_id,username,password,cert_flag,ca_flag[,path]// 参数说明// linkID0 : 连接 ID单连接模式固定为 0// scheme1 : 认证方式1用户名密码认证// client_id : 华为云分配的完整 ClientID含时间戳等// username : 设备标识通常等于 DEVICEID// password : 动态生成的 token由设备密钥 时间戳等计算得出// cert_flag0 : 不使用证书因不支持 TLS// ca_flag0 : 不校验 CAcharcmd[256]ATMQTTUSERCFG0,1,\690028b2e41f2979315c5cd2_esp8266-01_0_0_2025103102\,\690028b2e41f2979315c5cd2_esp8266-01\,\32ba9c69ce954354f912d54578bb3790a860ba89a7a011d7b3782aeb1a95b43c\,0,0,\\\r\n;// 2. 构造 MQTT 连接指令ATMQTTCONN// 格式ATMQTTCONNlinkID,host,port,keepalive// 注意端口必须为 1883非 8883因为 ESP8266 AT 固件不支持 TLS 加密charcmd2[256]ATMQTTCONN0,\c80c8bf1c5.st1.iotda-device.cn-north-4.myhuaweicloud.com\,1883,0\r\n;/* * 注以下为动态拼接版本更灵活但当前硬编码已通过测试 * sprintf(cmd, ATMQTTUSERCFG0,1,\%s\,\%s\,\%s\,0,0,\\\r\n, * MQTT_CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD); */// 3. 短暂延时确保上一步 WiFi 连接完全稳定Delay_ms(1000);// 4. 发送 MQTT 用户参数配置// 成功响应OKif(ESP8266_SendAT(cmd,OK,2000)){printf(MQTT CFG FAIL\r\n);return1;}printf(MQTT CFG SUCCESS\r\n);// 5. 【可选但推荐】显式设置 ClientID部分固件要求// 虽然 ATMQTTUSERCFG 已包含 ClientID但某些 ESP8266 AT 版本需单独设置if(ESP8266_SendAT(ATMQTTCLIENTID0,\690028b2e41f2979315c5cd2_esp8266-01_0_0_2025103102\\r\n,OK,2000)){printf(%s\r\n,WiFi_RxBuffer);printf(MQTT ClientID FAIL\r\n);return1;}printf(MQTT ClientID SUCCESS\r\n);// 6. 设置全局标志位 flag1// 作用在 ESP8266_SendAT() 中触发额外 3 秒延时应对 MQTT 连接慢的问题flag1;// 7. 发起 MQTT 连接// ⚠️ 关键成功响应是 MQTTCONNECTED不是 OK// OK 仅表示指令被接受MQTTCONNECTED 才表示真正连上服务器if(ESP8266_SendAT(cmd2,MQTTCONNECTED,2000)){printf(%s\r\n,WiFi_RxBuffer);// 打印实际返回便于排查错误如 DNS 失败、认证失败printf(MQTT CONNECT FAIL\r\n);return2;}printf(MQTT CONNECT SUCCESS\r\n);// 8. 【调试用】查询当前 MQTT 连接状态// 响应示例MQTTCONN:0,1 表示连接 ID0 已连接ESP8266_SendAT(ATMQTTCONN?\r\n,OK,2000);printf(%s\r\n,WiFi_RxBuffer);// 打印状态确认连接正常return0;// 全部成功}STM32控制ESP8266发送AT指令向云平台发送数据/** * brief 将温湿度数据以 JSON 格式通过 MQTT 上报至华为云 IoT 平台 * note 华为云要求 * - 主题Topic固定为$oc/devices/{device_id}/sys/properties/report * - 消息体为严格格式的 JSON包含 service_id 和 properties * - 属性名Temperature/Humidity必须与产品模型定义完全一致 * param temp: 温度值单位°C * param humi: 湿度值单位%RH */voidESP8266_SendDataToHuawei(floattemp,floathumi){// 1. 构造符合华为云规范的 JSON 数据体// 示例输出// {services:[{service_id:Tem_Hum_Data,properties:{Temperature:25.0,Humidity:60.0}}]}//// ⚠️ C 字符串中双引号需转义为 \// ⚠️ 而 JSON 本身又要求 key因此最终需写成 \\\ 即\ \// \\ → 在 C 中表示一个反斜杠 \ // \ → 在 C 中表示一个双引号 // 合起来 \\\ → 最终字符串中是 \// 发送给 ESP8266 后MQTT 消息体才是合法 JSONkeychardata[128];sprintf((char*)data,{\\\services\\\:[{\\\service_id\\\:\\\Tem_Hum_Data\\\\\,\\\properties\\\:{\\\Temperature\\\:%.1f\\,\\\Humidity\\\:%.1f}}]},temp,humi);// 2. 构造完整的 ATMQTTPUB 指令// 格式ATMQTTPUBlinkID,topic,payload,qos,retain// 参数说明// linkID 0 : 连接 ID单连接模式// topic $oc/.../report : 华为云设备属性上报专用主题// payload data : 上述 JSON 字符串// qos 0 : QoS 等级华为云通常用 0 或 1// retain 0 : 不保留消息charcmd[512];sprintf((char*)cmd,ATMQTTPUB0,\$oc/devices/%s/sys/properties/report\,\%s\,0,0\r\n,DEVICEID,data);/* * 注下方被注释的写法是错误的原因 * sprintf(cmd, ...\{\services...}\,..., temp, humi); * → C 编译器会认为 \{\ 是字符串结束 {变量}导致语法错误或非法 JSON */// 3. 发送 AT 指令并等待响应// 成功标志OK表示指令被 ESP8266 接受并成功发布if(ESP8266_SendAT(cmd,OK,2000)){// 若失败打印实际返回内容便于调试如 ERROR、FAIL 等printf(%s\r\n,WiFi_RxBuffer);printf(向华为云发送数据失败\r\n);}else{printf(向华为云发送数据成功\n);printf(Tem:%.1f,Hum:%.1f\r\n,temp,humi);}}主函数#includestm32f10x.h#include../System/Delay.h#include../Hardware/Key.h#include../Hardware/LED.h#include../Hardware/OLED.h#include../Hardware/USART1.h#include../Hardware/USART2.h#include../Hardware/WiFi.h#include../Hardware/DHT11.hintmain(){DHT11_Init();OLED_Init();USART1_Init();USART2_Init();// 初始化ESP8266并连接WiFiwhile(ESP8266_InitWiFi()!0){Delay_ms(1000);// 失败则重试}// 连接华为云MQTTwhile(ESP8266_ConnectHuaweiCloud()!0){Delay_ms(1000);// 失败则重试}// 循环发送数据floattemp,humi;while(1){DHT11_Read_Data(temp,humi);ESP8266_SendDataToHuawei(temp,humi);//temp 0.5f; // 模拟数据变化//humi 0.3f;//if (temp 35.0f) temp 25.0f;//if (humi 70.0f) humi 60.0f;Delay_ms(5000);// 每5秒发送一次}}效果展示