尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32+ESP8266+DHT11温湿度监测系统实战:从硬件连接到数据上云

STM32+ESP8266+DHT11温湿度监测系统实战:从硬件连接到数据上云 最近在做一个小型环境监测项目打算把办公室角落里的温湿度数据实时传到手机上看。选型时几乎没犹豫就定了STM32ESP8266DHT11OLED这套组合主控用STM32F103C8T6通信交给ESP8266传感器用DHT11显示用0.96寸OLED。这套方案在嵌入式圈子里算是经典得不能再经典的入门搭配网上资料多、踩坑记录全、成本压到五十块以内关键是做完之后你能真正理解一颗MCU是怎么把传感器数据变成网络数据的。这篇文章就围绕这套系统从硬件连接、时序驱动、数据上云到问题排查把我实际做过的完整流程和踩过的坑都写出来。适合刚学完STM32基础、想做一个完整物联网小项目的朋友参考也适合想快速验证ESP8266模块用法的同学直接抄作业。1. 这套方案到底在做什么在做任何一个项目之前先把需求想清楚比什么都重要。这个项目的本质需求其实只有一句话把传感器采集到的温湿度数据通过无线网络发送到远程端同时在本地设备上显示出来。听起来简单但拆开之后就涉及四个关键模块的协作每个模块的职责都比较清晰。1.1 四颗芯片的分工先看看这套系统里的每个角色都在干嘛。STM32F103C8T6是整个系统的大脑负责所有逻辑控制。它要干的事情包括定时读取DHT11的数据、解析温湿度值、把数据发给OLED显示、再通过串口把数据塞给ESP8266模块。选择STM32而不是直接用ESP8266的GPIO去读DHT11原因很简单ESP8266的AT固件模式下用户程序跑在MCU里ESP8266只做透传这样逻辑更清晰出错也好排查。ESP8266在这套方案里是通信兵。它本身也是一颗可以独立编程的芯片但在大多数入门项目里它跑的是官方AT固件STM32通过串口向它发送AT指令就能控制它连接网络、建立TCP连接、发送数据。这种做法的好处是开发门槛非常低你不需要去折腾ESP8266的SDK和编译环境只要会串口收发就能上手。DHT11是温湿度采集前端。它内部有一个电阻式湿度传感器和一个NTC热敏电阻通过单总线协议把数据传给MCU。精度虽然一般湿度±5%RH温度±2℃但对于环境监控这种场景已经够用。关键是它便宜、电路简单、驱动代码也不复杂特别适合用来理解单总线通信协议。OLED屏是本地显示终端。0.96寸的I2C接口OLED分辨率128x64功耗低、对比度高、显示效果好。它能实时显示当前温湿度和WiFi连接状态这样调试的时候不用开着串口助手也能直观看到系统在干什么。1.2 为什么选这套组合而不是其他方案有人可能会问既然ESP8266本身就能跑代码为什么还要加一颗STM32确实用ESP8266直接读DHT11、驱动OLED、上报数据技术上完全可行而且成本更低、体积更小。但作为学习项目STM32ESP8266的组合有它的独特价值。STM32是绝大多数嵌入式学习者入门的第一颗芯片GPIO操作、定时器、串口中断、I2C这些基本功都要在STM32上练。这个项目把STM32的串口、GPIO、I2C都用上了相当于一次综合实训。而ESP8266则承担了连接互联网这个新技能点让你知道MCU是怎么通过AT指令和外部通信模块协作的。另外从工程角度看主控和通信模块分离也更符合真实产品的设计思路。很多工业设备就是工业级MCU加通信模块的组合主控负责逻辑和可靠运行通信模块只做数据管道这样后期升级通信方案比如换成4G模块时主控代码几乎不用大改。至于传感器为什么不选DHT22或者SHT30理由也简单DHT11零门槛。它的单总线协议虽然时序要求严格但GitHub上大把现成驱动可以参考拿来学习正合适。等你把DHT11搞明白了后面换DHT22、SHT30也就是改改驱动的事。2. 硬件连接与初始化先把地基打牢这套系统的硬件连接不算复杂但有几个细节处理不好就会让后面调试很痛苦。我做的第一版就因为在ESP8266的供电上偷懒导致模块频繁重启折腾了一个晚上才找到原因。2.1 元器件清单与选型细节核心器件清单如下STM32F103C8T6最小系统板一个蓝色板带USB转串口ESP8266-01S或ESP8266-12F模块一个DHT11温湿度传感器模块一个买集成模块别买裸片0.96寸OLED屏幕一块I2C接口4针的那种若干杜邦线、面包板5V/3.3V电源USB供电就行选型的时候有几个坑要提醒一下。ESP8266模块尽量选ESP-01S不要选老版的ESP-01因为老版ESP-01下载IO0和IO2没引出调试不方便而且01S改了天线匹配电路信号更好。DHT11一定要买模块版而不是裸片模块上集成了上拉电阻和去耦电容直接插面包板就能用裸片还要自己搭外围电路麻烦且容易出错。OLED屏注意买I2C接口的四针VCC、GND、SCL、SDA别买成SPI接口七针的虽然SPI刷新更快但接线多、驱动复杂对这个项目来说I2C完全够了。2.2 引脚分配与接线表我的接线方式比较常规都是市面上教程最常见的接法方便你对照参考模块引脚STM32引脚DHT11DATAPA0DHT11VCC3.3VDHT11GNDGNDOLEDSCLPB6I2C1_SCLOLEDSDAPB7I2C1_SDAOLEDVCC3.3VOLEDGNDGNDESP8266TXPA10USART1_RXESP8266RXPA9USART1_TXESP8266VCC3.3VESP8266GNDGNDESP8266CH_PDEN3.3V这里有个关键点ESP8266的RX接的是STM32的TXPA9TX接的是STM32的RXPA10这是交叉接法串口通信的基本规矩。很多人第一次接的时候会把TX对TX、RX对RX结果数据完全不通这一点一定要记牢。2.3 关于供电和电平的注意事项ESP8266的供电是整个项目里最容易出问题的地方。这个模块在发射WiFi信号的瞬间电流会冲到300mA甚至更高如果你用STM32板上那个AMS1117稳压器供电电压会被瞬间拉低模块就会重启。我踩过的坑就是这个问题现象是ESP8266每隔几秒就重启一次串口输出乱码。解决办法有两个。第一尽量用外部5V稳压模块单独给ESP8266供电比如用一个LM2596降压模块或者直接找USB转TTL的5V输出脚供电。第二如果你一定要用3.3V供电那就在ESP8266的VCC和GND之间并一个大电容比如470uF电解电容用来缓冲电流尖峰。实测加了电容之后模块稳定性明显提升。关于电平匹配也要说一句。STM32的串口是3.3V逻辑电平ESP8266也是3.3V逻辑电平两者直接相连没问题。但如果你的USB转TTL工具是5V的千万别直接用它给ESP8266下载固件需要加电平转换电路否则大概率烧模块。我在调试初期就烧坏过一个ESP-01血泪教训。OLED和DHT11接3.3V就行这两个器件功耗很低不会对供电造成压力。整个系统用电脑USB口供电绰绰有余。3. DHT11与OLED的驱动细节硬件接好之后第一件事不是急着写ESP8266的通信代码而是先把DHT11和OLED调通。这两个模块调通之后系统就有了本地显示和数据采集能力再往后接网络才不至于两眼一抹黑。3.1 DHT11的通信时序拆解DHT11用的是单总线协议也就是说数据线只有一根既做传输又做接收而且时序要求非常严格。第一次写DHT11驱动的朋友通常会在这个地方卡住因为不理解它那个起始信号应答40bit数据的完整过程。完整通信过程分成四步。第一步主机STM32把数据线拉低至少18ms然后再拉高20-40us这是起始信号告诉DHT11我要开始读数据了。第二步DHT11收到起始信号后会拉低数据线约80us作为应答然后再拉高约80us表示我准备好了。第三步DHT11开始连续发送40bit数据每一位数据都是以50us的低电平开始然后高电平持续时间长短来表示0或1——高电平约26-28us表示0高电平约70us表示1。第四步数据发送完毕后数据线被拉低50us然后释放总线完成一次通信。这40bit数据是有结构的前16位是湿度数据整数小数中间16位是温度数据整数小数最后8位是校验和。校验规则很简单前四个字节相加如果低8位等于校验字节说明数据有效。驱动代码里最容易出问题的就是位时间判断。在实际写代码时我建议用定时器捕获而不是纯延时轮询来判断高电平持续时间精度更高。如果非要用延时的方案那就要把延时函数校准得非常准否则在时序边缘就会误判0和1。3.2 初始化DHT11的常见坑DHT11的上电启动时间比较长。很多人在上电后立刻就去读数据结果读回来的全是0xFF或者校验失败。这是因为DHT11上电后需要一个稳定过程文档上写的是上电后要等1秒才能发送指令。另外一个常见的错误是每次读取DHT11的间隔不能太短。DHT11官方手册说读取周期最小间隔是1秒实际体验下来如果你的主循环里每100ms就去读一次DHT11会越来越迟钝表现为读到的数据不变或者通信异常。我在代码里加了一个软件定时器保证每次读取间隔至少1.5秒之后数据稳定多了。还有一点值得注意DHT11的DATA引脚在STM32端要配置成开漏输出并外接上拉电阻。如果你买的模块已经带了上拉电阻那直接用推挽输出也行。但如果用的是裸片接法一定要加一个4.7k-10k的上拉电阻否则数据线浮空时序根本没法看。3.3 OLED显示驱动的两种方案OLED的驱动代码在这个项目里相对简单因为它是I2C接口底层通信协议由STM32的硬件I2C外设处理你只需要关心显示逻辑。有两个方案可选。第一个方案是用ST官方的HAL库加STM32CubeMX初始化I2C然后移植一个开源的SSD1306驱动库。这些库通常提供了DrawPixel、DrawLine、DrawString等函数往里面传入坐标和字符串就能在OLED上显示内容。HAL库的好处是CubeMX帮你把I2C的时序配置、时钟使能、引脚复用全处理好了你不用面对寄存器的细节对于初学者很友好。第二个方案是老工程师喜欢的寄存器配置法直接用标准外设库或者HAL库底层的I2C寄存器操作来初始化SSD1306。这个方案代码更精简执行效率更高但理解难度也更高。对新手来说我不建议一开始就啃寄存器先用现成库把功能跑通然后回头再看库函数底层的实现学习路径更顺。不管用哪种方式OLED上要显示中文和英文字符集。SSD1306默认是英文字库一个字符占6x8像素。如果要显示中文你需要自己准备字模数组把汉字取模后写入Flash然后按坐标绘制。这个属于显示进阶玩法本项目先显示英文和数据就行中文可以放到后面的增强阶段。4. 数据上云的实现思路DHT11和OLED能正常工作之后就到了这个项目最有意思的部分让数据通过ESP8266传到网络上。这里我用的是最基础的AT指令方案逻辑清晰也方便你一步步看数据是怎么从STM32的串口流向WiFi再到达服务器的。4.1 配置ESP8266连接网络先把ESP8266模块通过USB转TTL接到电脑上用串口助手发AT指令做初始化测试。模块上电后第一件事是发送AT确认应答如果返回OK说明固件正常工作。接下来依次发送以下指令ATCWMODE1设置WiFi模式为Station模式也就是让ESP8266作为终端去连接路由器。ATCWJAP你的WiFi名称,你的WiFi密码连接指定的无线路由器。返回WIFI CONNECTED然后是WIFI GOT IP说明已成功获得IP地址。ATCIPSTARTTCP,192.168.1.100,8080建立一个到目标服务器的TCP连接。这里的IP地址和端口要改成你自己服务器的如果只是本地测试可以先连本机或者另一台电脑。ATCIPMODE1 ATCIPSEND开启透传模式并开始发送数据。透传模式下STM32发给串口的所有数据都会原封不动地通过TCP发向服务器非常方便。要退出透传模式需要发送再等一秒。这一套指令组合是整个ESP8266通信的基础。可以把它写成一个初始化函数放在STM32代码里上电后按顺序执行然后再进入主循环发送数据。4.2 数据发送与平台接收数据上报的逻辑是STM32每1.5秒读一次DHT11然后把温湿度格式化成一个字符串比如TEMP:25.0,HUM:60.0通过串口发给ESP8266。ESP8266在透传模式下会把这个字符串直接推送到TCP服务器的对应端口。如果你想让数据在网页上实时展示最简单的办法是用Node.js写一个TCP服务把收到的数据用WebSocket广播到浏览器页面。我当时的做法是用Python写了一个Flask服务后台开一个TCP线程接收ESP8266的数据然后通过SocketIO推送到前端页面手机和电脑浏览器都能实时查看。这里有个重要的工程细节ESP8266透传模式下偶尔会出现数据发送失败的情况。原因是TCP连接可能因为网络波动断开但STM32并不知道。解决办法是在STM32和ESP8266的通信中加一个简单的应用层心跳协议。比如STM32每隔10秒向ESP8266发送ATPING或者在应用层数据里加一个序号如果连续几次没有收到服务器确认就重新执行ATCIPSTART建立新连接。4.3 断线重连与异常处理数据显示乱码、丢包、断线这些都是我在实际调试中遇到过的问题。有个问题特别典型ESP8266在透传模式下如果服务器主动断开TCP连接模块会退出透传并输出CLOSED提示。这时候如果你没有处理这个状态STM32还在继续往串口写数据这些数据就全部丢失了。我后来在代码里增加了状态机机制。STM32的串口接收中断里会实时检查ESP8266返回的内容如果发现CLOSED或者ERROR字符串就置一个标志位主循环检测到标志位后会重新执行初始化流程重新连接TCP。这个改动虽然不大但对系统稳定性的提升非常明显实测可以做到断线后5秒内自动恢复。还有一种情况是WiFi信号本身不稳定导致ESP8266连接路由器失败。在程序初始化阶段我设置了最多重试10次连接路由器的逻辑每次失败后重启ESP8266模块通过GPIO控制CH_PD引脚拉低再拉高实测对信号不佳的场景有奇效。5. 我的调试过程与踩坑记录调试这个项目的过程中我积累了不少经验。下面挑几个比较典型的故障场景来复盘这些问题在搜索引擎里被问得非常多如果你的系统也出了类似现象可以对照排查。5.1 ESP8266 AT指令不响应故障现象是STM32发送AT指令ESP8266毫无反应。排查步骤我建议按顺序来。首先确认模块有没有正常上电用万用表量一下VCC引脚电压是否稳定在3.3V电压低于3.0V基本就是供电不足。其次检查TX和RX接线有没有交叉这是新手最容易犯的错误。然后确认USB转TTL工具的TXD要接ESP8266的RXDRXD接ESP8266的TXD共地也是必须的。如果这些都正常但模块还是没反应可能是模块进入了刷机模式。ESP8266的IO0引脚如果接地上电后模块会进入下载模式而不是运行模式此时就算发AT指令也不会有任何返回。解决办法是让IO0悬空或者接高电平重新上电。还有一个细节容易被忽略ESP8266上电后需要大约2秒的启动时间如果你在代码里上电后立刻发AT指令大概率收不到回复。正确做法是上电后延时3秒以上再开始发送AT指令。5.2 DHT11数据全零的问题我遇到过一次DHT11读回来的数据全部为0温度0.0湿度0.0非常诡异。检查接线、换传感器都没有效果。最后定位到问题是代码初始化顺序有误。DHT11的驱动代码要求在初始化时把数据线拉高至少1秒让传感器进入稳定状态。而我在初始化函数里配置完GPIO后就立刻开始读取没有给传感器留出稳定时间。解决办法是在DHT11初始化函数里加上1000ms的延时然后再执行第一次读取问题就消失了。如果你读回来的数据一直在固定值附近跳动而且精确到0还有一个可能是IO口没有正确配置成开漏输出加外部上拉。DHT11的数据线在没有外部上拉的情况下读回来的电平会异常导致解析出的数据永远是0。检查一下你买的是模块版还是裸片模块上的上拉电阻焊没焊。5.3 OLED屏幕显示乱码OLED显示乱码的原因通常有两个I2C速率不对和地址配置错误。SSD1306的I2C地址一般是0x788位地址或者0x3C7位地址不同厂家的模块地址可能不一样我拿到的一块屏是0x3C另一块就是0x3D。还有一个容易踩的坑是I2C时钟速率。SSD1306支持的最大I2C时钟是400kHz但有些国产屏的时序余量不足在400kHz下会乱码或者不亮。解决办法是手动把I2C时钟降到100kHz刷新速度会慢一点但稳定才是第一位的。最后补充一个经验级的建议OLED显示屏非常怕静电和带电插拔。在调试过程中如果你频繁插拔OLED的杜邦线很容易把屏幕驱动芯片击穿导致屏幕永久性花屏或者完全不亮。我烧坏过一块屏之后就再也不敢带电插拔了实验时都是先断电再改线。6. 进阶方向建议整套系统跑通之后你会对嵌入式物联网项目的完整链路有一个非常清晰的认识。如果觉得这个版本太基础、想继续深挖这里有几个方向可以参考。6.1 从查询模式改成中断或定时唤醒当前版本的STM32主循环一直在轮询DHT11并上报数据这在教学场景下没问题但真实产品不会这么干。可以考虑用STM32的低功耗模式加RTC唤醒每隔5分钟醒来一次读取传感器并上报然后又睡回去。这样电池供电的话续航可以从几小时提升到几个月。6.2 接入MQTT实现手机远程查看把ESP8266从TCP透传模式切换成MQTT模式对接上海量的免费MQTT服务器然后直接用手机上的MQTT调试工具订阅对应主题就能随时随地查看温湿度。MQTT协议相比裸TCP的好处是有主题订阅机制、有QoS消息可靠等级、天然支持多端接收。实现起来就是在ESP8266上跑MQTT客户端用AT指令或者直接刷入MQTT固件代码量也不大。6.3 传感器替换与多节点扩展DHT11的精度和响应速度在工业场景下确实不够看。你可以把传感器替换成SHT30或者DHT22驱动代码做一下适配就好。如果你有多个房间要监控还可以用ESP8266做多节点采集每个节点带一个传感器通过路由器统一汇聚到服务器。节点之间做时间同步和数据格式统一是很好的分布式系统练手项目。我个人在实际调试这套系统时最大的感受是越简单的模块越容易在细节上翻车。DHT11的时序、ESP8266的供电、OLED的I2C地址任何一个地方出问题都会让你觉得代码写得明明没问题却跑不通。所以我的习惯是每接入一个模块就单独测试一个模块每跑通一个功能就保存一版代码不要一口气把所有代码写完再上电调试那样出了问题就很难定位了。
返回列表