尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32+ESP8266+DHT11物联网温湿度采集与无线上报实战

STM32+ESP8266+DHT11物联网温湿度采集与无线上报实战 简介本资源是一个基于STM32F103微控制器的物联网温湿度数据采集与无线上传完整工程面向嵌入式初学者及IoT项目实践者解决环境参数感知、MCU外设驱动、WiFi模块AT指令通信与HTTP数据上报等典型开发问题。压缩包共224个文件含39个C源码如stm32f10x_usart.c、stm32f10x_tim.c等底层驱动、41个头文件h、40个编译中间文件o/d/crf以及Keil工程配置uvprojx、uvoptx、烧录镜像hex/axf和调试脚本keilkill.bat总大小4.05MB结构完整可直接编译下载运行。已有1901人学习下载涵盖DHT11单总线协议解析、ESP8266 Station模式配置、串口透传与JSON数据封装等关键实现配套代码注释清晰、模块划分合理特别适合掌握STM32ESP8266DHT11协同开发全流程的实战训练。1. 项目整体设计与资源盘点1.1 这套组合解决什么问题手里同时压着STM32F103、ESP8266和DHT11这三样东西的人大概率不是在跑纯学习例程而是要做一件具体的事把温湿度数据通过WiFi传出去。DHT11负责采集环境温湿度STM32F103作为主控负责读传感器、处理数据ESP8266则承担无线通信的脏活累活。三者各司其职组成了物联网终端设备里非常经典的一套最小可行方案。我做这套项目时的直接动机很简单实验室有个小机房空调温控不太靠谱需要一套能远程看温度和湿度的设备。当时手里正好有F103最小系统板、一块ESP8266-01S模块和一个DHT11蓝色方壳传感器于是就把它们拼了起来。做完之后发现这套组合的代码结构、通信协议和调试方法几乎覆盖了嵌入式物联网开发前期的全部基本功非常适合作为入门到进阶的过渡项目。这个项目适合谁参考两类人。一类是刚学完STM32标准库或HAL库、想做点实际东西的初学者通过它能把GPIO操作、串口通信、时序模拟这些零散知识点串起来另一类是准备用STM32做IoT网关或数据采集节点的开发者这套方案可以作为最小原型验证通信链路后再替换更强的传感器或WiFi模块。它的核心价值在于用最少的硬件和代码跑通一条完整的数据链路——采集、解析、组帧、无线上报。1.2 压缩包里通常有什么如果你下载过类似的rar包里面一般不会只有工程源码。按我自己的习惯和见过的大部分打包方式这类压缩包至少包含以下内容STM32F103的工程源码可能是标准库或HAL库版本包含DHT11驱动、串口驱动和ESP8266控制逻辑ESP8266的AT指令固件或刷机工具有些包会把固件一起塞进去原理图或接线说明一般是用AD或立创EDA画的简单连线图一份使用说明或调试笔记记录波特率、引脚定义、AT指令序列等关键参数。我拿到别人的包时第一步从来不是急着编译烧录而是先做资源盘点重点确认三件事固件库是标准库还是HAL库、ESP8266的固件版本是什么、串口波特率配置是多少。这三件事决定了后续所有操作的基础。如果包里的工程是用标准库写的而你手头只有HAL库的开发习惯编译报错会让你浪费一整个晚上。另外要注意的是很多压缩包里的注释和说明都是作者自己的环境参数比如他用的串口号、他用的GPIO引脚这些必须根据你自己的板子重新核对。我见过不少人直接从网上下载工程不检查引脚定义就烧录结果DHT11接在PA0而代码里写的是PB1死活读不到数据还以为是传感器坏了。2. 硬件连接与DHT11采集细节2.1 接线方案与供电设计硬件连接是这套系统里最简单、也最容易出问题的一环。三块硬件的接线关系如下STM32F103与DHT11DHT11的DATA引脚接STM32的一个普通GPIO我习惯用PA0因为方便调试时用示波器或逻辑分析仪抓波形。VCC接3.3V或5V都可以DHT11的供电范围是3.3V~5.5V但强烈建议统一用3.3V避免电平不匹配的问题。GND共地这是必须的。STM32F103与ESP8266ESP8266的VCC接3.3V注意ESP8266-01S在WiFi发射瞬间电流峰值可达300mA以上如果用STM32板载的AMS1117-3.3稳压芯片供电容易导致电压跌落、模块重启。最好用独立的3.3V稳压模块或USB供电分开供电共地即可。UTXD接STM32的PA2USART2_TXURXD接PA3USART2_RXCH_PDEN引脚必须拉高接3.3V或通过10K电阻上拉否则模块不工作。GPIO0在正常运行时悬空或接高电平这是进入运行模式的条件。我第一版布线时偷懒直接用开发板的3.3V给ESP8266供电结果现象非常经典程序跑起来串口调试助手能收到DHT11的数据但ESP8266要么没响应要么发AT指令偶尔收到OK偶尔无响应。用万用表一量ESP8266的VCC在发送数据时被拉低到2.7V左右瞬间掉电重启。后来单独供电后问题立刻消失。供电问题还容易出现在用面包板搭电路时。面包板的电源轨本身有接触电阻大电流下压降明显。如果条件允许直接用杜邦线把ESP8266的VCC和GND接到独立稳压模块的输出端线长尽量短线径尽量粗。这个项目里大部分诡异问题根源都是供电不稳而不是代码有bug。2.2 DHT11时序解析与代码实现DHT11是单总线协议只有一根数据线时序要求比较严格。它的通信流程是主机发送起始信号拉低至少18ms然后释放DHT11响应后拉低80us再拉高80us表示准备好然后开始输出40位数据。这40位数据里8位湿度整数、8位湿度小数、8位温度整数、8位温度小数、8位校验和。校验和的算法很简单前四个字节相加结果低8位等于校验字节就说明数据有效。每一位数据的读取是靠高电平的持续时间区分的。DHT11输出每一位时都会先拉低50us然后拉高如果高电平持续26~28us代表逻辑0如果持续70us左右代表逻辑1。所以读数据的核心操作就是等待引脚变低再等待引脚变高然后测量高电平的持续时间超过某个阈值判为1否则判为0。用STM32的HAL库实现时关键是不能使用HAL_Delay因为HAL_Delay基于SysTick在GPIO高速翻转时容易受影响。我用的方案是DWTData Watchpoint and Trace计数器做微秒级延时精度高且不占用定时器。DWT是Cortex-M3内核自带的调试组件初始化后通过读取DWT-CYCCNT来计时。核心代码结构如下// DWT延时初始化 void DWT_Init(void) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; } // 微秒延时 void DWT_Delay_us(uint32_t us) { uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000); while ((DWT-CYCCNT - start) ticks); } // 读取DHT11单字节 uint8_t DHT11_ReadByte(void) { uint8_t data 0; for (int i 0; i 8; i) { while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_RESET); // 等待50us低电平结束 DWT_Delay_us(40); // 延时40us后采样 if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { data | (0x80 i); // 高电平持续较长判为1 while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET); // 等待高电平结束 } } return data; }这个读取方法用的是“延时40us后采样”的思路如果高电平是26us的逻辑040us后早已变低如果是70us的逻辑140us后仍然是高。实测下来非常稳定比反复测量高电平宽度再比较的方法省时间也不容易卡死在等待循环里。读取DHT11的完整流程是拉低引脚18ms以上释放并上拉等待DHT11拉低响应信号再等待响应信号结束然后连续读取40位数据。需要注意每次读取间隔要大于1秒DHT11的采样周期最慢是0.5Hz你读得太频繁它会来不及更新数据返回的全是上一次的结果。2.3 采集稳定性的几个关键坑DHT11采集这块最容易踩的坑有四个都是实际调试中遇到的问题写了代码也不一定能马上发现。第一个坑是主机起始信号时间不够。DHT11的数据手册要求低电平时间大于18ms我最初图省事只延时了5ms结果传感器完全不响应。排查了十几分钟才意识到是起始信号太短。后来改成20ms一次成功。这个延时做在DWT_Delay_us(20000)就行完全不用怕时间太长影响什么DHT11不响应的时候拉低多久都不会坏。第二个坑是GPIO模式切换。DHT11是单总线主机既要输出低电平发起始信号又要释放总线等待从机响应所以要在一开始把引脚配置为开漏输出并外接上拉电阻或者动态切换推挽输出和上拉输入两种模式。我用的是开漏输出加外部10K上拉这样输出低电平时正常拉低释放时则靠上拉电阻维持高电平省去模式切换的麻烦。如果用推挽输出模式需要在发送完起始信号后手动把引脚切回输入模式这一步漏了的话总线一直被拉低DHT11没法应答。第三个坑是引脚悬空导致误读。有些STM32板子内部上拉电阻阻值偏大DHT11数据线悬空时电平不稳定读取结果会出现偶发的0xFF或校验错误。解决办法是外部加一个4.7K~10K的上拉电阻到3.3V。这个电阻推荐加不加也能跑但稳定性会差不少尤其是在环境电磁干扰较强的场合。第四个坑是连续读取时总线冲突。如果你把DHT11读取放在主循环里不加间隔或者用定时器中断频繁触发DHT11可能在一次读取流程还没结束时就收到新的起始信号导致时序错乱。我吃过这个亏用定时器1秒触发一次采集结果定时器中断偶发嵌套DHT11返回的数据变成了全1。后来把所有DHT11单个字节读取函数都加上了超时退出机制超过一定时间没等到电平变化就直接返回错误避免死循环。3. ESP8266接入与数据上行3.1 ESP8266的三种工作方式ESP8266这块很多初学者最先搞混的就是STA、AP和STAAP三种模式的区别。在这个项目里我们用的是STA模式即让ESP8266作为一个WiFi客户端连接家里的路由器或手机热点然后把数据发给服务器。STA模式ESP8266连接外部路由器相当于手机连WiFi适合数据上报场景AP模式ESP8266自己开热点其他设备连它适合配网或本地控制场景STAAP模式同时连接路由器又开热点适合需要远程控制和本地调试并存的场景。实际项目中如果你想把数据传到公网服务器用STA模式就够了。AP模式一般用在首次配置WiFi信息的时候——ESP8266开热点手机连上后用网页或App设置SSID和密码设置完成后切回STA模式。有些成熟方案会做成“SmartConfig”或微信配网但这对ESP8266-01S来说不太方便因为需要额外的库支持。对于STM32ESP8266这种组合我倾向于直接用AT指令手动配置简单直观出了问题也容易定位。这里要强调一点ESP8266模块本身是可以跑SDK独立工作的不依赖STM32。你完全可以用AT指令直接让ESP8266读取DHT11并上传数据毕竟ESP8266也有GPIO。但在这个项目里我们选择STM32作为主控逻辑其实很清晰——ESP8266只负责收发数据不承担业务逻辑这样后续如果要换WiFi模块比如换成ESP32-C3或W5500有线网卡主控代码不需要大改只替换通信层。这种“主控通信模块”的分层架构是很多物联网设备的通用设计。3.2 AT指令联调与固件确认用AT指令操作ESP8266第一步不是写代码而是用USB转TTL模块把ESP8266单独接出来在电脑串口助手上手动测一遍指令。这一步必须做因为你得确认三件事模块固件是AT固件还是NodeMCU固件、AT指令的波特率是多少、模块是否能正常响应。市面上很多ESP8266-01S出厂固件版本和波特率不统一我见过默认115200的也见过9600和57600的盲写代码指定波特率纯粹是赌运气。接线方式很简单USB转TTL的TX接ESP8266的URXDRX接UTXD共地VCC接3.3VCH_PD接高电平。打开串口助手选好波特率发送AT如果收到OK说明模块正常。如果没反应先用115200试不行换9600/57600都不用的话按住GPIO0接地再上电进入下载模式重新刷AT固件包。固件这块我的经验是尽量用较新的AT固件至少支持TCP透传ATCIPMODE1。因为温湿度上传场景最常用的就是TCP连接到服务器后直接透传数据老固件不支持透传的话每次发送都要带ATCIPSEND指令代码复杂度高不少。确认固件支持透传的方式很简单发送ATCIPMODE?如果返回OK CIPMODE:1就是支持。固件版本没必要追最新够用就行。我手头这块ESP8266-01S用的是乐鑫官方2020年左右发布的AT固件跑透传非常稳定连续上传7天数据没有一次掉线。刷固件用的是esptool.py这是乐鑫官方的开源烧录工具命令行操作跨平台兼容比Flash Download Tool更适合批量操作和集成到自动化脚本中。刷的时候注意ESP8266必须进入UART下载模式GPIO0接地再上电VCC要单独供电CH340这类USB转TTL芯片的3.3V输出带不动ESP8266建议外部供电。3.3 数据封装与发送数据要发送首先得确定格式。最简单的方案是拼接成一行字符串通过串口发送AT指令给ESP8266让它通过TCP或UDP上报到服务器。我最开始用UDP因为服务器端不用处理连接状态丢包也无所谓反正温湿度数据每秒都在变丢了下一帧还能补上。后来因为要保证数据到达率改成了TCP长连接通过ATCIPSTARTTCP,服务器IP,端口号建立连接然后ATCIPMODE1进入透传模式之后所有通过串口发给ESP8266的数据都会被原样转发到服务器。这里的数据帧格式我建议直接用JSON虽然对嵌入式设备来说JSON解析和组包会占用一些RAM但好处是服务器端解析方便可扩展性好。一个典型的帧格式如下{id:dev01,temp:26.5,humi:60.2,ts:1710000000}STM32端要做的工作很简单用sprintf函数把DHT11读取到的整数和小数部分拼进字符串然后通过串口发送给ESP8266。需要注意sprintf默认会把浮点数打印成26.50这样的格式占用的RAM较多对于F103这种只有20KB RAM的芯片不建议直接用%f格式打印浮点数。更稳妥的做法是把温度湿度拆成整数和小数两个变量手动拼接。比如温度读取结果是26.5度就把26存到temp_int5存到temp_dec用%d.%d格式打印省去浮点数格式化的开销。char buf[64]; sprintf(buf, {\id\:\dev01\,\temp\:%d.%d,\humi\:%d.%d,\ts\:%lu}\r\n, temp_int, temp_dec, humi_int, humi_dec, timestamp);TIMESTAMP这里的处理有个讲究。STM32没有RTC模块或者没有网络对时的话本地时间是不可信的。你可以通过ATCIPSNTPTIME?指令让ESP8266走SNTP服务器对时但需要AT固件支持CIPSNTPCFG指令老固件不一定有。我的方案是服务器收到数据后以自己的接收时间为准打上时间戳入库设备端不传时间。这样既省了设备端的工作量也避免了设备时钟不准导致的数据时间错乱。在发送节奏上我实测下来最稳定的间隔是5秒一次。太快了TCP连接上的小包太多容易触发Nagle算法导致数据延迟太慢了温湿度数据的实时性又达不到。如果你用的是UDP可以适当提高到1秒一次TCP的话5秒比较舒服。4. 联调过程与典型问题排查4.1 上电联调的完整流程硬件接好、代码写完后联调阶段最容易让人崩溃。原因是这条链路太长DHT11时序、STM32串口发送、ESP8266的AT指令响应、TCP连接建立、服务器端接收解析任何一个环节出错现象都可能是“没数据”或“数据不对”你很难一眼看出问题出在哪。我建议按以下顺序分层验证每层确认无误后再进入下一层第一层验证DHT11采集。只烧录DHT11读取程序把温度和湿度通过USART1打印到电脑串口助手波特率115200。如果串口能稳定打印出合理的温湿度值比如室温25度、湿度50%左右说明DHT11驱动正常。这一步实测最可能的问题是DHT11数据脚接错、上拉电阻缺失、起始信号时间不够。第二层验证ESP8266的AT响应。用STM32的USART2接ESP8266烧录一个简单的回环测试程序把USART1接收到的字符转发给USART2再把USART2接收到的内容转发回USART1。这样你可以在电脑上直接用串口助手发送AT指令通过STM32中转给ESP8266看ESP8266是否回复OK。这一步的本质是确认STM32与ESP8266之间的串口通信参数一致。第三层验证WiFi连接和TCP上报。在电脑上打开一个TCP服务器可以直接用网络调试助手然后让STM32通过ESP8266连接这个局域网IP端口主动上报数据。如果你在公司或家里局域网内这一步不需要公网IP方便快速验证。能收到数据后再考虑部署到公网服务器。第四层验证公网服务器接收。把TCP服务器的IP换成公网服务器的IP注意服务器端防火墙要放行对应端口ESP8266连接公网IP比连局域网IP多一个NAT穿透的过程。如果连不上先用手机在相同WiFi环境下测试能访问服务器端口排除网络本身的问题。每一层验证通过后再进入下一层这样排查效率最高。跳过中间步骤直接联调遇到问题就要同时怀疑DHT11、STM32、ESP8266和服务器四个环节非常被动。4.2 常见问题速查表联调过程中我把自己踩过的坑和帮别人解决问题的经验整理成了一份速查表按现象分类方便直接对照现象可能原因排查与解决DHT11一直返回0xFF数据线没接对或悬空检查GPIO复用配置加4.7K~10K上拉电阻DHT11偶发校验错误时序延时不准改用DWT延时不要用HAL_Delay做微秒延时DHT11温度读数明显偏高传感器离MCU发热源太近如果板载稳压芯片发热严重传感器远离它或者外接传感器头ESP8266发AT无响应波特率不对或未上电进运行模式用USB转TTL单独测试逐一遍历9600/57600/115200ESP8266连接WiFi失败SSID或密码错误发送ATCWJAPSSID,密码后用ATCWJAP?查询连接状态ESP8266连上WiFi但TCP连不上服务器服务器IP端口不通本机用telnet测试服务器端口检查防火墙规则TCP连接正常但发送数据服务器收不到数据后没有换行或服务器解析问题确认帧格式里有回车换行服务端按行读取或检查JSON完整性运行一段时间后ESP8266离线供电不足导致模块重启独立供电并确认3.3V输出能力大于500mAESP8266偶发返回busy状态正在处理上一条指令发送指令间隔加大或等待ATCIPSTATUS返回非busy再发下一条这条表格里最值得说的是最后一行。ESP8266的AT固件有个特点它处理完一条指令后返回的结果和OK之间可能有几百毫秒的延迟尤其是在连接TCP或DNS解析时串口上可能先打印一些IP地址信息、CONNECT信息然后才返回OK。如果STM32端给ESP8266发完一条AT指令不等任何回复就紧接着发下一条非常容易出现busy状态和数据丢失。我的解决办法是定义一个简单的状态机每条AT指令发送后等待收到OK或ERROR再发下一条。这个状态机逻辑也不复杂就是判断串口接收缓冲区的关键字。4.3 HTTP与MQTT怎么选在ESP8266上报数据这条路上很多初学者纠结到底用TCP裸传、HTTP还是MQTT我的个人建议是先分清你的场景再决定。如果只是自己搭一个简单的Web页面用TCP裸传最简单。服务器端开一个Socket监听端口收到数据后解析JSON入库前端用WebSocket或轮询从库或缓存里拿数据展示。这种方式代码最少不需要额外部署中间件适合快速原型验证。我自己第一版就是这样做的——Python写个Socket服务器收到数据后打印到控制台并写入SQLite前端用Flask渲染页面一个周末搞定。如果数据要接入现有平台比如OneNet、腾讯云IoT或自己的EMQX集群那就直接用MQTT。MQTT的好处是协议层已经解决了连接管理、消息QoS、离线消息等问题ESP8266通过AT指令集里的ATMQTTUSERCFG、ATMQTTCONN等命令需要固件支持MQTT功能连接brokerSTM32端只需要把数据拼好发给ESP8266即可。MQTT的缺点是要维护一个broker如果只是自己用部署成本比TCP裸传高不少。如果数据要展示在公网网页上而且你不打算维护服务器可以试试HTTP POST到一些免费的数据上报平台比如各种IoT云平台。但这种方式对ESP8266 AT固件来说交互比较繁琐需要拼接HTTP头、处理响应码代码量明显增加。我试过一次就不想用第二次除非平台给了专门的SDK或简单封装否则还是TCP或MQTT省心。我的最终选择是TCP长连接透传。原因很简单调试直观、代码量小、依赖最少。ESP8266进入透传模式后STM32端完全不需要关心协议细节只管往串口扔数据服务器收到什么就是什么。这个方案唯一的弱点是TCP连接如果断了需要重新执行ATCIPSTART。所以我加了个简单的重连机制定时查询ESP8266的连接状态ATCIPSTATUS如果返回不是CONNECTED状态就重新发起连接。5. 写在最后的几句实在话这套STM32ESP8266DHT11的小项目我前前后后搭了两版第一版用的标准库第二版换成了HAL库。换库的主要原因不是标准库不好用而是HAL库在底层的时钟配置和GPIO抽象上更规范后面接其他传感器模块时代码复用性明显更好。我个人在实际操作中最大的体会是这种级别的项目真正的难点不在任何一个单独的模块而在于把三个模块串起来。DHT11的时序问题、ESP8266的供电问题单拎出来都能在网上找到答案但当你把它们放在同一条数据链路上时问题就会互相干扰比如ESP8266的供电波动导致DHT11读数异常这种组合问题只能靠分层排查一步步定位。最后再分享一个小技巧联调过程中给DHT11采集的数据加上一个递增序号比如每帧数据里的最后一个字段是帧计数。这样你就能从服务器端的数据里直接看出有没有丢帧、乱序以及WiFi通信是否有延迟——数据间隔时间突然变长说明链路有阻塞序号跳变说明有丢帧。这个小小的调试字段能帮你省下大量排查通信问题的时间。项目跑稳定后再把这个字段去掉也不迟。本文还有配套的精品资源点击获取
返回列表