都会明武电子 LOGO 都会明武电子电子模块 · 技术支持
STM32F103C8T6 · DHT11 + Relay + 4-Key Threshold · Learning Kit

STM32 传感器学习套件

复用 HC-SR04+OLED 的同一块蓝丸接线基础,换成 DHT11 测温 + 4键手动调阈值 + 继电器/马达温控的练习项目。

1

概述

Overview

这是在 HC-SR04_STM32_OLED版 项目基础上做的一个独立练习:HC-SR04 超声波模块拿掉了,STM32+OLED 的接线原样保留,换上了 DHT11 温湿度传感器、一路继电器(带马达/负载)、一颗指示灯,再加一组4键做"温度触发阈值"的实时手动调节。

核心逻辑很简单:DHT11 每隔几秒测一次实际温度,跟当前设定的阈值比较,一旦温度超过阈值就自动吸合继电器、点亮指示灯,带动马达或其它负载工作;阈值本身可以用4个按键现场 +/- 调整,不用重新编译烧录。

跟 HC-SR04_STM32_OLED版 的关系

两个是完全独立的 PlatformIO 工程,互不影响。原项目专门做 HC-SR04 测距,已经发布过 B站STM32详解视频;这个是同一块板子的另一个练习,代码在 固件\STM32_传感器学习套件\ 单独一份。

2

硬件接线

Wiring
部件引脚说明
OLED (SSD1306, I2C, 0x3C)SCL=PB8, SDA=PB9GND/VCC 用 PB6/PB7 两个 GPIO 模拟供电(拉低当地、拉高当3.3V),仅限 OLED 这种<20mA 低功耗外设才能这样接
DHT11 温湿度传感器数据脚 = PB13VCC/GND 直接接 3.3V/GND(不要接5V,见第7节坑①)
继电器模块信号脚(IN) = PB12VCC 要接模块实际标称电压(这次用的是12V继电器,见第7节坑④)
指示灯 (10mm 黄灯)PA1反接线(负极接MCU、正极接3.3V),GPIO拉低才亮
手动强制按键PC14另一端接3.3V,内部下拉,按下为高电平
4键温度调节PA3 (ADC)黄/绿/红/蓝4个按键做分压,实测raw ADC:黄507/绿559/红713/蓝854

⚠ 马达(或其它负载)一定要接在继电器的 COM + NO

NO(常开)才是"继电器吸合=导通"的那一对端子;接到 NC(常闭)上会正好相反——继电器吸合反而断开,之前调试时被这个坑绕晕过,见第7节坑⑤。

3

工作原理动图

How It Works

完整工作周期:DHT11测温 → STM32比较阈值 → 超过阈值继电器吸合(NO导通) → 马达转+黄灯亮 → OLED刷新显示 → 循环。

STM32传感器学习套件工作原理动图
Pillow 逐帧手绘动图,生成脚本见 动画制作脚本\make_sensorkit_gif.py,改颜色/时序参数重新跑一遍即可。

实拍 · 真实硬件演示(2026-07-25),按键调阈值、继电器/马达动作、串口数据跟硬件同框对照,原始素材未剪辑配音。
4

使用说明

Controls

开机默认阈值 30°C。DHT11 实测温度只要严格超过当前阈值(等于不算),继电器和黄灯就自动开启;温度回落到阈值以下,自动关闭。

4键:实时调阈值按一下就生效,不用一直按住

阈值 +1°C
绿阈值 -1°C
阈值 +5°C(快调)
阈值 -5°C(快调)
阈值范围限制在 15°C ~ 50°C 之间,OLED"Threshold"那一行实时显示当前值

PC14:手动强制开关

单击切换(锁存),不是按住才生效。按一下强制打开继电器+黄灯(不管温度),再按一下取消强制、恢复自动温控判断。OLED上"Relay: ON (manual)"里的"(manual)"就是手动强制生效的标志。


串口:直接发数字设阈值

eagleCom发送框输入一个整数(比如 32)点发送/回车,直接把阈值设成32°C,跟4键调节共用同一个变量,两种方式随便混用。只解析整数部分,不支持小数。

5

串口输出字段说明

Serial Monitor Fields

CP2102接法:GND-GND,TXD→STM32的PA10,RXD→STM32的PA9(交叉接),VCC悬空不接。eagleCom/任意串口工具打开对应COM口,波特率115200,会看到这样连续打印的一行:

串口输出示例
Temp: 30 C, Humidity: 40 %, Threshold: 30 C, raw ADC: 0, Manual: off, Relay: off

字段含义
TempDHT11 实测的当前温度(整数摄氏度)。每2秒更新一次;读取失败时沿用上一次的有效值。
HumidityDHT11 实测的当前湿度(整数百分比),跟 Temp 同一次采样得到。
Threshold当前生效的触发阈值,开机默认30°C,靠4键 +/- 实时调整,断电不保存、重新上电会回到30°C。
raw ADCPA3引脚实时读到的原始模拟值(STM32为12位ADC,范围0~4095)。等于0表示没有键被按住;按下黄/绿/红/蓝会分别跳到约506/558/712/854,固件靠这4个数值区间判断按的是哪个键。
ManualPC14手动强制开关的锁存状态,ON=强制模式生效(不看温度),off=按自动温控逻辑判断。
Relay继电器/黄灯的最终执行状态:Manual=ON 或者 Temp>Threshold 任一成立就是 ON,两个都不成立才是 off。
DHT11 读取失败时

不会只打印笼统的失败,而是打印具体卡在哪一步:no response (line stuck HIGH)=完全没响应(查接线/供电),timeout waiting bit-start=某个数据位超时,checksum mismatch=数据能收到但校验和不对。三种对应完全不同的排查方向,见第7节坑①②。

6

完整代码

main.cpp

PlatformIO 工程,platform = ststm32board = bluepill_f103c8framework = arduinoupload_protocol = stlink。Windows下中文路径会导致GCC链接器报错,编译烧录前记得先复制到纯英文路径。

固件\STM32_传感器学习套件\src\main.cpp
加载中…
7

踩过的坑

Lessons Learned

都是这次调试实测出来的,不是猜的:

  1. DHT11引脚记录错误:一开始以为接的是PB1,实际接的是PB13,代码读错引脚导致"完全没响应",加了失败原因诊断后才定位到。
  2. DHT11超时余量太紧:最初握手信号超时设的100µs,跟实际80µs信号比起来余量太小,STM32duino的digitalRead()调用开销就可能把余量吃掉导致误判超时,后来放宽到150-200µs解决。
  3. 继电器触发方向搞反:一开始假设常见的"低电平触发",但这个模块跳线实际设的是"高电平触发",方向反了继电器完全不吸合,改成高电平触发才对。
  4. 继电器额定电压搞错:一开始以为是5V继电器,实际这个模块是12V的,3.3V/5V都不够让线圈吸合,只有指示灯会亮(信号侧OK)但线圈不动——这跟触发方向是两个独立问题,不要混着排查。
  5. NC/NO接反:马达一开始接在NC(常闭)上,导致"继电器吸合→马达反而停"这种跟预期完全相反的效果,容易被误判成继电器坏了或者阈值算反了。改接到NO(常开)后行为才符合直觉。
  6. 室温常年30+度,固定阈值测不出效果:最初4档写死28/30/32/34°C,室温本来就在30-31°C,等于有几档永远是ON,测不出"关"的对照效果。后来把"选4个固定档"整个改成了"+/-实时调节",从根本上解决了"阈值要跟着环境温度变"这个问题。
  7. ST-Link/CP2102 USB连接不稳定:调试过程中反复出现掉线,都是拔插一下USB线(换个口更稳)就恢复,是这批USB转接模块的通病,不是驱动或代码问题。
  8. atof()意外让Flash暴涨:加"串口输入数字设阈值"功能时最初用atof()解析字符串,Flash占用从55.8%直接跳到79.3%(多了15KB)——atof/strtod会把整套C库的浮点字符串解析代码链接进来,体积很大。这个场景只需要整数精度,改成手写的逐字符累加解析后Flash掉回56.2%。只需要整数精度的场合,尽量别用atof/sprintf浮点格式化这类标准库函数。