概述
Overview这是在 HC-SR04_STM32_OLED版 项目基础上做的一个独立练习:HC-SR04 超声波模块拿掉了,STM32+OLED 的接线原样保留,换上了 DHT11 温湿度传感器、一路继电器(带马达/负载)、一颗指示灯,再加一组4键做"温度触发阈值"的实时手动调节。
核心逻辑很简单:DHT11 每隔几秒测一次实际温度,跟当前设定的阈值比较,一旦温度超过阈值就自动吸合继电器、点亮指示灯,带动马达或其它负载工作;阈值本身可以用4个按键现场 +/- 调整,不用重新编译烧录。
两个是完全独立的 PlatformIO 工程,互不影响。原项目专门做 HC-SR04 测距,已经发布过 B站STM32详解视频;这个是同一块板子的另一个练习,代码在 固件\STM32_传感器学习套件\ 单独一份。
硬件接线
Wiring| 部件 | 引脚 | 说明 |
|---|---|---|
| OLED (SSD1306, I2C, 0x3C) | SCL=PB8, SDA=PB9 | GND/VCC 用 PB6/PB7 两个 GPIO 模拟供电(拉低当地、拉高当3.3V),仅限 OLED 这种<20mA 低功耗外设才能这样接 |
| DHT11 温湿度传感器 | 数据脚 = PB13 | VCC/GND 直接接 3.3V/GND(不要接5V,见第7节坑①) |
| 继电器模块 | 信号脚(IN) = PB12 | VCC 要接模块实际标称电压(这次用的是12V继电器,见第7节坑④) |
| 指示灯 (10mm 黄灯) | PA1 | 反接线(负极接MCU、正极接3.3V),GPIO拉低才亮 |
| 手动强制按键 | PC14 | 另一端接3.3V,内部下拉,按下为高电平 |
| 4键温度调节 | PA3 (ADC) | 黄/绿/红/蓝4个按键做分压,实测raw ADC:黄507/绿559/红713/蓝854 |
NO(常开)才是"继电器吸合=导通"的那一对端子;接到 NC(常闭)上会正好相反——继电器吸合反而断开,之前调试时被这个坑绕晕过,见第7节坑⑤。
工作原理动图
How It Works完整工作周期:DHT11测温 → STM32比较阈值 → 超过阈值继电器吸合(NO导通) → 马达转+黄灯亮 → OLED刷新显示 → 循环。
使用说明
Controls开机默认阈值 30°C。DHT11 实测温度只要严格超过当前阈值(等于不算),继电器和黄灯就自动开启;温度回落到阈值以下,自动关闭。
4键:实时调阈值按一下就生效,不用一直按住
单击切换(锁存),不是按住才生效。按一下强制打开继电器+黄灯(不管温度),再按一下取消强制、恢复自动温控判断。OLED上"Relay: ON (manual)"里的"(manual)"就是手动强制生效的标志。
eagleCom发送框输入一个整数(比如 32)点发送/回车,直接把阈值设成32°C,跟4键调节共用同一个变量,两种方式随便混用。只解析整数部分,不支持小数。
串口输出字段说明
Serial Monitor FieldsCP2102接法: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
| 字段 | 含义 |
|---|---|
| Temp | DHT11 实测的当前温度(整数摄氏度)。每2秒更新一次;读取失败时沿用上一次的有效值。 |
| Humidity | DHT11 实测的当前湿度(整数百分比),跟 Temp 同一次采样得到。 |
| Threshold | 当前生效的触发阈值,开机默认30°C,靠4键 +/- 实时调整,断电不保存、重新上电会回到30°C。 |
| raw ADC | PA3引脚实时读到的原始模拟值(STM32为12位ADC,范围0~4095)。等于0表示没有键被按住;按下黄/绿/红/蓝会分别跳到约506/558/712/854,固件靠这4个数值区间判断按的是哪个键。 |
| Manual | PC14手动强制开关的锁存状态,ON=强制模式生效(不看温度),off=按自动温控逻辑判断。 |
| Relay | 继电器/黄灯的最终执行状态:Manual=ON 或者 Temp>Threshold 任一成立就是 ON,两个都不成立才是 off。 |
不会只打印笼统的失败,而是打印具体卡在哪一步:no response (line stuck HIGH)=完全没响应(查接线/供电),timeout waiting bit-start=某个数据位超时,checksum mismatch=数据能收到但校验和不对。三种对应完全不同的排查方向,见第7节坑①②。
完整代码
main.cppPlatformIO 工程,platform = ststm32,board = bluepill_f103c8,framework = arduino,upload_protocol = stlink。Windows下中文路径会导致GCC链接器报错,编译烧录前记得先复制到纯英文路径。
加载中…
踩过的坑
Lessons Learned都是这次调试实测出来的,不是猜的:
- DHT11引脚记录错误:一开始以为接的是PB1,实际接的是PB13,代码读错引脚导致"完全没响应",加了失败原因诊断后才定位到。
- DHT11超时余量太紧:最初握手信号超时设的100µs,跟实际80µs信号比起来余量太小,STM32duino的digitalRead()调用开销就可能把余量吃掉导致误判超时,后来放宽到150-200µs解决。
- 继电器触发方向搞反:一开始假设常见的"低电平触发",但这个模块跳线实际设的是"高电平触发",方向反了继电器完全不吸合,改成高电平触发才对。
- 继电器额定电压搞错:一开始以为是5V继电器,实际这个模块是12V的,3.3V/5V都不够让线圈吸合,只有指示灯会亮(信号侧OK)但线圈不动——这跟触发方向是两个独立问题,不要混着排查。
- NC/NO接反:马达一开始接在NC(常闭)上,导致"继电器吸合→马达反而停"这种跟预期完全相反的效果,容易被误判成继电器坏了或者阈值算反了。改接到NO(常开)后行为才符合直觉。
- 室温常年30+度,固定阈值测不出效果:最初4档写死28/30/32/34°C,室温本来就在30-31°C,等于有几档永远是ON,测不出"关"的对照效果。后来把"选4个固定档"整个改成了"+/-实时调节",从根本上解决了"阈值要跟着环境温度变"这个问题。
- ST-Link/CP2102 USB连接不稳定:调试过程中反复出现掉线,都是拔插一下USB线(换个口更稳)就恢复,是这批USB转接模块的通病,不是驱动或代码问题。
- atof()意外让Flash暴涨:加"串口输入数字设阈值"功能时最初用atof()解析字符串,Flash占用从55.8%直接跳到79.3%(多了15KB)——atof/strtod会把整套C库的浮点字符串解析代码链接进来,体积很大。这个场景只需要整数精度,改成手写的逐字符累加解析后Flash掉回56.2%。只需要整数精度的场合,尽量别用atof/sprintf浮点格式化这类标准库函数。