STM32温湿度采集与无线传输实战:从DHT11驱动到低功耗状态机
发布时间:2026/10/18 13:10:04 锦皓数字建站

简介这份资源是一份基于STM32的温湿度检测与无线传输毕业设计文档面向自动化、电子信息及嵌入式方向的在校学生与初学者帮助其理解从数据采集到无线通信的完整设计思路。文档围绕STM32单片机展开涵盖芯片选型、CC1020无线模块、SHT10温湿度采集、LCD1602显示及上下位机交互构想并涉及电路设计与程序设计等关键环节。资源包内共1个doc文件约10.83MB内容为完整的毕业设计论文包含摘要、引言、芯片模块介绍与硬件方案说明适合作为课程设计或论文写作的参考模板。目前已有72人学习下载读者可从中获取STM32外设配置、无线传输方案选型及温湿度检测系统的整体架构思路对嵌入式入门与项目实践具有较高的借鉴价值。1. 从一份毕设文档说起STM32 温湿度采集与无线回传到底该怎么落地前阵子帮一个做嵌入式方向的朋友看他的毕设材料文件名就叫「基于STM32的温湿度检测和无线的传输(1).doc」。打开一看典型的课程设计文档需求写得挺全DHT11 接哪个引脚、LCD1602 怎么显示、无线模块怎么发数据但真到动手环节很多人卡在「传感器读出来全是 0」「无线发出去收不到」「电池撑不过一天」这些具体问题上。这份资源的价值就在这儿——它把 STM32 最小系统、温湿度传感器、无线传输模块和上位机显示串成了一条完整链路适合正在做嵌入式课程设计、毕业设计或者想快速搭一个环境监测原型的开发者。不管你是刚接触 HAL 库的新手还是想找个现成框架改参数的老手这份文档都能当施工图用。下面我按实际复现顺序把选型、接线、代码和踩坑点拆开讲。2. 硬件选型与接线为什么是 STM32F103 DHT11 无线串口模块2.1 主控与传感器的搭配逻辑STM32F103C8T6 这颗芯片在课程设计和原型验证里出场率极高原因很实在72MHz 主频、64KB Flash、20KB RAM跑温湿度采集和串口收发绰绰有余关键是资料多、价格低、最小系统板随手能买到。温湿度传感器选 DHT11 还是 DHT22得看精度要求。DHT11 温度精度 ±2℃、湿度 ±5%RH够应付一般环境监测DHT22 能到 ±0.5℃ 和 ±2%RH但价格翻几倍。如果文档里没特别指定我一般先用 DHT11 把链路跑通后面要精度再换 PIN 对 PIN 兼容的 DHT22。无线传输部分这份资源用的是串口透传模块方案常见的有基于 LoRa 的、基于 2.4G 的也有直接走 Wi-Fi 的。选型时盯三个参数传输距离、接口类型、供电电压。课程设计场景下几十米到几百米距离、TTL 串口接口、3.3V 或 5V 供电的模块最省事。注意模块的默认波特率很多出厂是 9600和 STM32 串口配置不一致就是收不到数据的头号原因。接线这块DHT11 的数据脚接 PA0无线模块的 TX 接 STM32 的 RX比如 PA10RX 接 STM32 的 TXPA9供电共地。别小看共地我见过至少三例「模块灯亮但没数据」最后查出来是地没接。模块引脚接 STM32 引脚备注DHT11VCC3.3V供电要稳DHT11DATAPA0需 4.7K 上拉电阻DHT11GNDGND共地无线模块TXPA10 (USART1_RX)交叉连接无线模块RXPA9 (USART1_TX)交叉连接无线模块VCC3.3V/5V看模块规格无线模块GNDGND共地2.2 时钟与串口配置的实操步骤用 CubeMX 建工程时时钟树先把 HSE 选上主频拉到 72MHz。USART1 配置成异步模式波特率和无线模块保持一致数据位 8、停止位 1、无校验。DHT11 那根数据线配置成开漏输出加外部上拉或者推挽输出配合 4.7K 电阻。定时器开一个微秒级延时DHT11 的时序对延时精度有要求HAL_Delay 的毫秒级不够用。// dht11.c 关键时序主机拉低至少 18ms 后释放 void DHT11_Start(void) { GPIO_InitTypeDef gpio {0}; gpio.Pin GPIO_PIN_0; gpio.Mode GPIO_MODE_OUTPUT_PP; gpio.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, gpio); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); HAL_Delay(20); // 拉低 20ms留余量 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); delay_us(30); // 释放 30us 等待响应 gpio.Mode GPIO_MODE_INPUT; gpio.Pull GPIO_PULLUP; HAL_GPIO_Init(GPIOA, gpio); }这段代码的逻辑是先把数据脚切输出模式拉低持续 20ms 给 DHT11 一个明确的起始信号然后释放总线并切回输入模式等传感器拉低 80us 再拉高 80us 作为响应。参数上拉低时间不能少于 18ms释放后的等待窗口要卡在 20 到 40us 之间太短读不到响应太长会错过第一个数据位。delay_us 建议用定时器实现别用空循环不同优化等级下空循环的耗时差异能让你怀疑人生。3. 数据采集与无线发送从单次读取到稳定回传的完整代码链路3.1 DHT11 读时序与校验和DHT11 一次完整读取返回 40 位数据湿度整数、湿度小数、温度整数、温度小数、校验和。校验和等于前四个字节相加取低八位。读的时候每一位以 50us 低电平开始高电平持续 26 到 28us 表示 0持续 70us 表示 1。这个判断窗口很窄所以读位函数里不能用 HAL_Delay得用微秒延时配合 GPIO 读取。// 读取一个字节返回 0 或 1 组成的 8 位数据 uint8_t DHT11_ReadByte(void) { uint8_t data 0; for (int i 0; i 8; i) { while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET); // 等低电平结束 delay_us(40); // 跳过 26-28us 的 0 高电平 data 1; if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_SET) { data | 1; // 仍是高电平说明是 1 } while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_SET); // 等位结束 } return data; }逻辑说明第一个 while 等 50us 起始低电平过去然后延时 40us 采样。如果此时还是高电平说明这一位的高电平超过了 40us判定为 1否则判定为 0。参数上40us 这个采样点要卡在 28us 和 70us 之间留出足够裕量。读完后要等引脚变低准备下一位。整个读取过程建议关中断不然一个串口中断进来时序就乱了。3.2 无线发送的数据帧格式无线模块走串口透传意味着你发什么它就发什么接收端收到的一模一样。所以帧格式得自己定。我一般用「帧头 长度 数据 校验 帧尾」的结构接收端按帧头对齐避免数据错位。// 打包并发送温湿度数据 void Send_Sensor_Data(uint8_t temp, uint8_t humi) { uint8_t frame[8]; frame[0] 0xAA; // 帧头 frame[1] 0x02; // 数据长度 frame[2] temp; // 温度 frame[3] humi; // 湿度 frame[4] temp humi; // 简单校验和 frame[5] 0x55; // 帧尾 HAL_UART_Transmit(huart1, frame, 6, 100); }参数说明帧头选 0xAA 是因为二进制里 10101010 跳变多接收端容易识别长度字段告诉接收方后面有几个有效字节校验和用累加取低八位能挡住大部分单字节错误帧尾 0x55 和帧头配对方便接收端做边界判断。HAL_UART_Transmit 的超时设 100ms太短了在波特率低的时候发不完太长了阻塞主循环。如果数据量大建议改用 DMA 发送别在中断里调这个函数。3.3 主循环的调度节奏主循环里别把采集和发送绑死在一起。DHT11 两次读取之间至少间隔 1 秒读太快传感器内部状态没复位数据会漂。无线发送可以每 2 秒一次或者变化超过阈值再发省电。我一般这么排while (1) { if (HAL_GetTick() - last_read 2000) { // 2 秒读一次 if (DHT11_Read(temp, humi) 0) { // 返回 0 表示成功 Send_Sensor_Data(temp, humi); } last_read HAL_GetTick(); } // 其他任务 }这里用 HAL_GetTick 做软定时不占用硬件定时器。注意 DHT11_Read 失败时不要立刻重试等下一个周期连续重试反而容易把传感器搞进异常状态。4. 避坑排查调不通时先看这五个地方4.1 现象DHT11 读出来全是 0 或 255原因时序不对最常见的是微秒延时不准。用 HAL_Delay 代替微秒延时或者空循环在不同优化等级下耗时不同都会导致采样点偏移。另一个原因是数据脚没上拉DHT11 是开漏输出没上拉电阻读不到高电平。解决用定时器做微秒延时或者用 DWT 周期计数器。数据脚确认接了 4.7K 到 10K 的上拉电阻。用逻辑分析仪抓一下起始信号看拉低时间是不是够 18ms。4.2 现象无线模块发送正常但接收端收不到原因波特率不匹配占七成剩下三成是接线 TX/RX 没交叉。有些模块出厂波特率是 9600但代码里配的是 115200发出去的数据接收端解析全是乱码。还有模块需要先发配置命令进入透传模式直接发数据它不转发。解决先用 USB 转串口工具单独测模块确认波特率和模式。TX 接对方的 RXRX 接对方的 TX别接成 TX 对 TX。共地一定要接。4.3 现象数据偶尔跳变温度突然到 80 多度原因DHT11 读取过程中被中断打断时序错位导致读到位错误。或者电源纹波大传感器供电不稳。解决读取 DHT11 的那几毫秒关总中断读完再开。电源脚并一个 100nF 加 10uF 的电容。如果还跳降低读取频率到 3 秒一次。4.4 现象系统跑一段时间后死机原因串口发送用了阻塞模式无线模块响应慢的时候 HAL_UART_Transmit 一直等看门狗没喂导致复位。或者栈溢出局部数组开太大。解决串口发送改 DMA 或中断模式别用阻塞。检查启动文件里的栈大小STM32F103 默认 1KB局部大数组改全局或静态。开独立看门狗主循环里按时喂。4.5 现象接收端数据错位帧头对不上原因发送端和接收端的帧格式定义不一致或者接收端缓冲区没做环形处理数据覆盖了。解决把帧格式写成文档两边对着改。接收端用环形缓冲区加状态机解析别用数组硬存。帧头检测到之后按长度字段收够字节再校验校验不过就丢弃重新找帧头。5. 进阶技巧用状态机重构接收端与低功耗优化接收端如果还用「收一个字节判断一次」的写法数据量一上来就丢包。我后来改成状态机加环形缓冲区稳定很多。状态机四个状态等帧头、收长度、收数据、收校验。每来一个字节推进一次状态校验不过就回到等帧头。typedef enum { WAIT_HEAD, GET_LEN, GET_DATA, GET_CHECK } rx_state_t; void Rx_StateMachine(uint8_t byte) { static rx_state_t state WAIT_HEAD; static uint8_t buf[32], idx 0, len 0; switch (state) { case WAIT_HEAD: if (byte 0xAA) state GET_LEN; break; case GET_LEN: len byte; idx 0; state (len 0 len 32) ? GET_DATA : WAIT_HEAD; break; case GET_DATA: buf[idx] byte; if (idx len) state GET_CHECK; break; case GET_CHECK: if (byte 0x55) { // 校验并处理 buf 里的数据 } state WAIT_HEAD; break; } }这个状态机的关键是每个状态只做一件事不阻塞。环形缓冲区用头尾指针中断里只写指针主循环读指针不用关中断。低功耗方面如果设备用电池供电把采集间隔拉到 10 秒以上无线模块发完就进休眠STM32 进 STOP 模式RTC 定时唤醒。实测下来两节 5 号电池能撑一个月左右。从那以后我每次做无线采集项目都强制先把接收端状态机跑通再调发送端不然数据一多就成黑匣子根本不知道丢在哪。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。