news 2026/10/27 17:00:21

STM32温湿度采集报警系统实战:DHT11时序、代码与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32温湿度采集报警系统实战:DHT11时序、代码与避坑指南

简介:这份资源是面向嵌入式初学者与STM32开发者的温湿度采集报警系统完整工程包,围绕环境监测与超限报警场景展开,可用于农业、仓储、智能家居等方向的课程设计或练手项目。压缩包共204个文件,约3.29MB,以52个c源文件与43个h头文件为核心,配合30个d依赖文件、30个o目标文件、28个crf编译中间文件,以及uvprojx工程文件、sct分散加载文件、hex烧录文件等,构成可直接编译的Keil工程结构。内容涉及DHT系列单总线传感器的时序配置与数据解析、ADC采样、GPIO与定时器初始化、串口通信驱动,以及基于中断机制的阈值判断与蜂鸣器、LED或无线模块报警逻辑,代码注释与分层结构便于理解硬件交互流程。目前已有4799人学习下载,适合希望掌握STM32外设驱动、传感器通信与报警系统设计的读者参考借鉴。

1. 从一份“温湿度采集报警系统”压缩包说起:STM32 上最容易翻车的小系统

很多人第一次接触 STM32 项目,都是从温湿度采集报警系统开始的。它看起来简单:一个传感器读温湿度,一个单片机做判断,超限就报警。但真正动手做,你会发现坑比想象中多——传感器时序不对、串口打印乱码、报警阈值抖动、蜂鸣器一响程序就跑飞。这份“基于 STM32 的温湿度采集报警系统 + 源代码”压缩包,本质上就是一套最小可用的物联网感知节点方案,适合刚学完 GPIO 和串口、想找一个完整项目练手的嵌入式新手,也适合需要快速搭一个环境监测原型的工程师。它解决的核心问题很明确:把温湿度数据稳定采集上来,在本地做超限判断,并通过声光或串口输出报警。下面我按实际落地顺序,把选型、接线、代码结构、参数设置和常见翻车点拆开讲,你照着做就能跑通,也能看清哪些地方值得投入时间优化。

2. 硬件选型与最小系统搭建:DHT11、STM32F103 和报警外设怎么配

2.1 为什么常见方案是 DHT11 + STM32F103 + 蜂鸣器/LED

温湿度采集报警系统的硬件选型,市面上最常见的组合是 STM32F103C8T6 最小系统板、DHT11 温湿度传感器、有源蜂鸣器和 LED。选 DHT11 不是因为它精度高,而是因为它便宜、单总线协议简单、资料多,适合验证逻辑。DHT11 的湿度测量范围 20%~90%RH,精度 ±5%RH,温度范围 0~50℃,精度 ±2℃,采样周期不低于 1 秒。如果你需要更准的数据,可以换 DHT22 或 SHT30,但代码时序要改。STM32F103C8T6 有足够的 GPIO 和定时器,价格低,标准库和 HAL 库资料都全。报警外设用有源蜂鸣器最省事,给高电平就响,不需要 PWM 驱动;LED 用来做视觉指示,方便调试时确认报警状态。

接线方面,DHT11 的数据脚接 STM32 的某个 GPIO,比如 PA0,同时接一个 4.7kΩ~10kΩ 上拉电阻到 3.3V。蜂鸣器信号脚接 PB0,LED 接 PB1,都串联限流电阻。供电统一用 3.3V,DHT11 虽然标称 3.3V~5.5V,但和 STM32 共 3.3V 时电平匹配最稳。注意 DHT11 的电源脚和地脚不要接反,反接一次传感器基本就废了,这是血泪经验。

2.2 最小系统搭建步骤与供电检查

搭建顺序建议按以下步骤走,避免一上来就焊死所有线:

  1. 先把 STM32 最小系统板用 USB 转 TTL 模块连接电脑,确认能通过串口打印“Hello”之类的测试信息,证明下载和串口都正常。
  2. 单独给 DHT11 接 3.3V 和 GND,数据脚先悬空,用万用表测电源电压是否稳定在 3.3V 附近。
  3. 把 DHT11 数据脚接到 PA0,加上拉电阻,再下载一个只读 DHT11 的测试程序,串口观察数据。
  4. 最后接蜂鸣器和 LED,下载完整报警程序,用吹风机或湿布改变温湿度,观察报警动作。

供电检查容易被忽略:如果 STM32 和 DHT11 由不同电源供电,或者 USB 供电电流不足,DHT11 会返回校验和错误。常见现象是串口打印“DHT11 Error”或数据全 0。解决方法是统一用板载 3.3V 稳压输出,或者给 DHT11 单独加 100nF 去耦电容。

2.3 报警外设的驱动方式与参数选择

有源蜂鸣器只需要 GPIO 输出高电平就能响,但要注意电流。STM32 单个 GPIO 最大输出 20mA,而蜂鸣器工作电流可能到 30mA,所以最好用三极管驱动,比如 S8050,基极串 1kΩ 电阻接 GPIO,集电极接蜂鸣器负极,发射极接地,蜂鸣器正极接 3.3V。LED 同样串 220Ω~1kΩ 限流电阻。如果你用的是无源蜂鸣器,就需要 PWM 输出方波,频率 2kHz~4kHz 声音最响,这时候要占用一个定时器通道。

报警逻辑上,我一般设两个阈值:温度上限 35℃,湿度上限 80%RH。超过就蜂鸣器响、LED 快闪;低于下限 10℃ 或 20%RH 则 LED 慢闪,蜂鸣器不响,避免夜间吵人。阈值不要设得太接近日常环境值,否则数据一抖动就频繁报警,看起来像玄学,其实是阈值太窄。

3. 源代码结构拆解:从 DHT11 时序到报警状态机

3.1 DHT11 单总线时序的代码实现与微秒级延时

DHT11 的通信协议是单总线,一次完整读取包括:主机拉低至少 18ms,然后拉高 20~40us,接着释放总线,DHT11 响应 80us 低电平 + 80us 高电平,之后连续输出 40 位数据,每位以 50us 低电平开始,高电平持续时间决定 0 或 1。代码里最关键的是微秒级延时,不能用 HAL_Delay,要用定时器或空循环校准。

下面是一段基于 STM32 标准库的 DHT11 读取核心代码,你可以直接抄到工程里:

// 微秒延时,基于 SysTick 或空循环,需根据主频校准 void delay_us(uint32_t us) { uint32_t i; for (i = 0; i < us * 8; i++); // 72MHz 下约 1us,需实测调整 } // 读取 DHT11 一个字节 uint8_t DHT11_ReadByte(void) { uint8_t i, byte = 0; for (i = 0; i < 8; i++) { while (DHT11_DATA_IN() == 0); // 等待 50us 低电平结束 delay_us(40); // 延时 40us 判断高电平持续时间 byte <<= 1; if (DHT11_DATA_IN() == 1) { byte |= 1; while (DHT11_DATA_IN() == 1); // 等待剩余高电平结束 } } return byte; } // 完整读取温湿度,返回 0 成功,1 失败 uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humi) { uint8_t buf[5]; // 主机发送起始信号 DHT11_DATA_OUT(); DHT11_DATA_LOW(); HAL_Delay(20); // 拉低至少 18ms DHT11_DATA_HIGH(); delay_us(30); // 拉高 20~40us DHT11_DATA_IN(); // 切换为输入,等待响应 if (DHT11_DATA_IN() == 0) { while (DHT11_DATA_IN() == 0); // 等待 80us 低电平响应 while (DHT11_DATA_IN() == 1); // 等待 80us 高电平响应 for (int i = 0; i < 5; i++) { buf[i] = DHT11_ReadByte(); } DHT11_DATA_OUT(); DHT11_DATA_HIGH(); // 校验和 if (buf[0] + buf[1] + buf[2] + buf[3] == buf[4]) { *humi = buf[0]; *temp = buf[2]; return 0; } } return 1; }

逻辑说明:delay_us 的循环次数需要根据你的 STM32 主频实测调整,72MHz 下空循环 8 次大约 1us,但编译器优化等级会影响,最好用示波器看波形。DHT11_ReadByte 里先等低电平结束,再延时 40us 采样,如果还是高电平就是 1,否则是 0。校验和判断能过滤大部分通信错误。参数上,拉低时间不能少于 18ms,拉高 20~40us 之间,太短 DHT11 不响应,太长也不影响但浪费。

3.2 主循环里的采集、判断与报警状态机

主循环不要用 delay 死等,建议用定时器或系统滴答做 1 秒周期任务。下面是一个简单的状态机框架:

typedef enum { STATE_NORMAL, STATE_ALARM_HIGH, STATE_ALARM_LOW } AlarmState; AlarmState state = STATE_NORMAL; uint8_t temp, humi; while (1) { if (DHT11_ReadData(&temp, &humi) == 0) { printf("Temp: %d C, Humi: %d %%RH\r\n", temp, humi); // 判断报警条件 if (temp > TEMP_HIGH || humi > HUMI_HIGH) { state = STATE_ALARM_HIGH; } else if (temp < TEMP_LOW || humi < HUMI_LOW) { state = STATE_ALARM_LOW; } else { state = STATE_NORMAL; } } else { printf("DHT11 read error\r\n"); } // 执行报警动作 switch (state) { case STATE_NORMAL: BEEP_OFF(); LED_OFF(); break; case STATE_ALARM_HIGH: BEEP_ON(); LED_TOGGLE(); // 快闪 break; case STATE_ALARM_LOW: BEEP_OFF(); LED_TOGGLE(); // 慢闪,可通过计数器分频 break; } HAL_Delay(1000); // 1 秒采集一次 }

逻辑说明:状态机把报警逻辑和硬件动作分开,方便扩展。TEMP_HIGH、HUMI_HIGH 等宏定义在头文件里,改阈值不用动主逻辑。LED_TOGGLE 快闪和慢闪可以通过计数器实现,比如快闪每 100ms 翻转,慢闪每 500ms 翻转。注意 DHT11 读取失败时不要立刻报警,而是保持上一次状态或进入错误提示,否则传感器偶尔出错会导致误报。

3.3 串口打印与数据格式:避免 GBK 转 UTF8 的乱码坑

串口打印是调试温湿度系统最常用的手段,但很多人会遇到中文乱码。STM32 标准库默认用 GBK 编码,而电脑串口助手如果设成 UTF-8 就会乱码。常见做法是串口只打印英文和数字,比如“Temp: 25 C, Humi: 60 %RH”,这样任何编码都不会乱。如果你非要打印中文,要么把串口助手编码改成 GBK,要么在代码里做 GBK 转 UTF8 的转换表,但后者很占空间,不推荐在资源紧张的 STM32F103 上做。

串口参数一般设 115200-8-N-1,波特率太高在长线或干扰环境下容易丢数据。打印频率不要太高,1 秒一次足够,否则串口缓冲区溢出会丢包。如果你用 printf,记得重定向 fputc 到串口发送函数,并在工程设置里勾选 Use MicroLIB。

4. 避坑与排查:温湿度采集报警系统最常见的 5 个翻车现场

4.1 现象:串口一直打印 DHT11 Error,数据全 0

原因:DHT11 时序不对,最常见的是 delay_us 不准,或者 GPIO 模式切换没做对。DHT11 数据脚在输出和输入之间切换时,必须重新配置 GPIO 方向,标准库用 GPIO_Init 重新初始化,HAL 库用 HAL_GPIO_DeInit 再 Init。另外上拉电阻缺失也会导致总线无法拉高。

解决:用示波器看 PA0 波形,确认起始信号拉低 18ms、拉高 30us,然后 DHT11 有响应。没有示波器就用逻辑分析仪,几十块钱的够用。delay_us 用定时器实现最准,比如 TIM4 做 1us 计数。

4.2 现象:温度值偶尔跳到 0 或 255,湿度正常

原因:DHT11 小数部分在高温高湿环境下可能不稳定,或者电源纹波大导致位判断错误。DHT11 的温度整数部分在 buf[2],小数在 buf[3],但很多代码只取整数,小数丢弃。如果 buf[2] 偶尔变成 0,可能是校验和通过但数据位错位。

解决:连续读三次,取中间值或平均值;电源脚加 100nF 和 10uF 电容;数据线尽量短,远离电机和继电器。

4.3 现象:蜂鸣器一响,串口就停止打印或程序复位

原因:蜂鸣器电流太大,拉低电源电压导致 STM32 复位。有源蜂鸣器直接接 GPIO 时,瞬间电流可能超过 20mA,而且反向电动势会干扰电源。

解决:用三极管驱动,蜂鸣器两端并联续流二极管,比如 1N4148。电源加 100uF 电解电容。如果还复位,检查复位引脚是否被干扰,加 100nF 电容到地。

4.4 现象:报警阈值附近数据频繁跳动,蜂鸣器断断续续

原因:没有做迟滞判断,温度在阈值上下 0.5℃ 波动时,状态机反复切换。DHT11 精度 ±2℃,本身就不适合做精确阈值判断。

解决:加迟滞区间,比如上限 35℃,只有超过 36℃ 才报警,低于 34℃ 才解除。湿度同理。或者用滑动平均滤波,连续 5 次超过阈值才触发报警。

4.5 现象:下载程序后不运行,必须按复位键

原因:STM32 的 BOOT0 和 BOOT1 跳线不对,或者下载器没有复位信号。常见于用串口下载时,BOOT0 接高电平进入系统存储器,下载完忘记接回 GND。

解决:检查 BOOT0 接地,BOOT1 任意。用 ST-Link 下载时勾选“Reset after download”。如果还不行,检查晶振是否起振,用示波器看 8MHz 晶振引脚。

5. 进阶技巧:用定时器中断做非阻塞采集与低功耗优化

如果你已经跑通了基础版本,下一步值得做的是把主循环里的 HAL_Delay(1000) 去掉,改成定时器中断触发采集。这样主循环可以处理按键、串口命令等其他任务,系统响应更快。具体做法:用 TIM2 配置 1Hz 中断,在中断里置位标志位,主循环检测标志位再调用 DHT11_ReadData。注意 DHT11 读取过程需要关中断或提高优先级,否则微秒延时会被打断。

低功耗方面,如果系统用电池供电,可以在采集间隔让 STM32 进入 Sleep 模式,定时器唤醒。DHT11 不采集时断电,用 GPIO 控制其电源脚。报警时再唤醒蜂鸣器。实测下来,这样可以把平均电流从 20mA 降到 2mA 左右。

验证方法:用串口打印时间戳,观察采集周期是否稳定在 1 秒;用万用表测电流,确认 Sleep 模式生效。我一般会保留一个调试宏,一键切换阻塞和非阻塞版本,方便对比。

最后说个习惯:每次改完代码,先读一遍 DHT11 的校验和,再打印原始 5 个字节,确认数据来源正确。这个后悔药能帮你省下大量排查时间。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 16:59:34

CAD矢量图在富文本编辑器的精准粘贴技术方案

1. 问题背景与行业痛点在芯片制造企业的日常研发流程中&#xff0c;CAD图纸的跨平台流转是个高频刚需。我接触过某半导体设备厂商的案例&#xff1a;他们的工艺工程师需要将AutoCAD设计的掩膜版图纸粘贴到企业知识管理系统的富文本编辑器&#xff08;TinyMCE&#xff09;中&…

作者头像 李华
网站建设 2026/10/27 16:58:35

用AI Agent重构Android APK逆向分析工作流

1. 为什么我会把 Android 逆向工程交给 AI Agent先讲一个让我下定决心做这个项目的场景。上个月我需要分析一个第三方 App 的资源文件结构和签名信息&#xff0c;整个流程说起来不复杂&#xff1a;解包、看 AndroidManifest、拉签名、确认目标 SDK 版本和权限声明&#xff0c;再…

作者头像 李华
网站建设 2026/10/27 16:58:05

YOLOv13中的CGA Fusion模块:多模态特征融合创新

1. 项目概述&#xff1a;YOLOv13中的CGA Fusion模块创新在目标检测领域&#xff0c;YOLO系列算法一直以其实时性和准确性著称。最新提出的YOLOv13在Neck部分引入了一项关键改进——CGA Fusion&#xff08;Content-Guided Attention Fusion&#xff09;模块。这个创新设计通过内…

作者头像 李华
网站建设 2026/10/27 16:57:40

本科生论文写作工具全攻略:从文献管理到格式排版

1. 本科生论文写作痛点与工具需求分析 写论文这件事&#xff0c;对本科生来说就像第一次下厨做满汉全席——明明连菜刀都拿不稳&#xff0c;却被要求端出一道米其林三星的菜品。我指导过上百名本科生的毕业论文&#xff0c;发现他们普遍面临三大困境&#xff1a; 第一是文献综…

作者头像 李华
网站建设 2026/10/27 16:56:26

基于STM32的电子血压计设计:示波法原理与算法实现

简介&#xff1a;基于STM32的电子血压计设计是一份可运行复现的嵌入式实践项目&#xff0c;面向电子竞赛、毕业设计及单片机入门学习者&#xff0c;用于解决血压测量系统的软硬件实现问题&#xff0c;帮助掌握STM32外设编程与传感器数据采集处理流程。资源压缩包共包含195个文件…

作者头像 李华