温湿度传感器(DHT11,单总线)
温湿度传感器(DHT11,单总线)
DHT11 是低成本温湿度模块,用单总线(One-Wire 风格)时序与 MCU 通信,常用于环境监测。本文为 STM32 驱动要点速查 + 洋桃1号实测档案(2026-09-19 OLED 中文显示改造)。
#一、元信息
| 字段 | 值 |
|---|---|
| 芯片/平台 | STM32F103C8T6(洋桃1号,官方例程 demo39 标准库;通用驱动写法见下,HAL 兼容) |
| 接口类型 | 单总线(One-Wire 时序,1 根数据线) |
| 验证状态 | ✅ 已验证 |
| 验证环境 | 洋桃1号 / Keil MDK(AC5)/ 2026-09-19:温湿度读数 + OLED 中文显示 + 串口每秒打印实测通过 |
| 驱动方式 | 位 bang 时序(精确延时 + GPIO 翻转) |
#二、接线表
| 信号 | MCU 引脚 | 模块引脚 | 备注 |
|---|---|---|---|
| DATA | PA15 | DHT11 OUT | ⚠️ 洋桃1号上与舵机信号脚共用,测 DHT11 前必须拔掉舵机排线(否则舵机乱动、DHT11 读不到数据);模块自带板载上拉,裸 DHT11 四针需 4.7kΩ 上拉到 3.3V |
| VCC | 3.3V | VCC | 3.3~5.5V |
| GND | GND | GND | 必须共地 |
| 串口观察(可选) | PA9(USART1_TX) | USB-TTL RX | 115200 8N1,GND 共地 |
#三、通信时序要点
- 起始信号:主机拉低 DATA ≥ 18ms,再拉高 20~40µs,释放总线。
- 从机响应:DHT11 拉低 80µs(应答),再拉高 80µs,然后开始发数据。
- 数据位:每 bit 先拉低 50µs,再拉高——高电平 26~28µs = 0,70µs = 1。靠高电平持续时间判 0/1。
- 数据帧:40 bit = 湿度整数 8 + 湿度小数 8(恒为 0)+ 温度整数 8 + 温度小数 8(恒为 0)+ 校验和 8。校验 = 前 4 字节之和低 8 位。
- 读取周期建议 ≥ 1s(两次采样间隔),连续读取过快会不响应——官方例程里两处
delay_ms(1000)(初始化后 + 主循环)都不能删。 - 温度分辨率只有 1℃、精度 ±2℃:室温稳定时"读数一直不动"通常是正常的,拿到空调风口吹一会儿验证。
#四、实测改造记录(2026-09-19)
在官方 Demo(英文界面)基础上做三处改造,全部上机验证:
① 串口每秒打印:工程没有现成串口,main.c 补 USART1 配置(PA9 AF_PP / PA10 浮空输入,115200),主循环 sprintf(s,"RH=%d%% T=%dC\r\n",...) 后逐字节 USART_SendData 发出。不直接用 printf 的原因见踩坑清单第 11 条(半主机)。
② 单位美化:字库里 % 的点阵圆圈只有 2×2 个点太细 → 重画(圆圈加大到 3×3、斜线加粗);字库没有 °(ASCII 没这个字符)→ 借位:把从来用不到的反引号 ` ` 的字模替换成度符号,代码里写 C ` 屏上显示 °C`。通用技巧:要用字库没有的符号,就找一个用不到的 ASCII 字符借位。
③ 中文化 + 居中:Humidity/Temperature → 汉字「湿度/温度」,两行水平居中。新字用取模软件生成,设置必须与屏驱动约定一致:
| 选项 | 值 |
|---|---|
| 取模方式 | 纵向8点下高位 |
| 数据排列 | 从左到右从上到下 |
| 字库 | 宋体16.dot |
| 输出格式 | C51(0x 前缀) |
一个汉字 32 字节,直接贴进 CHS_16x16.h。两个显示 API 的差异(易踩):OLED_DISPLAY_8x16 内部有 col+2 偏移(传 X-2 才显示在物理列 X);OLED_DISPLAY_16x16 没有偏移、第三个参数是 GB_16[] 数组索引(不是 ASCII 码),汉字占 page 与 page+1 两页。混排不补偿间距会不均。
#五、踩坑清单
- 上拉电阻必须有:裸 DHT11 的 DATA 需 4.7kΩ 上拉(模块版自带板载上拉);不上拉读不到稳定波形。
- 延时精度是命门:时序 µs 级,微秒延时用定时器/DWT 实现,且采样期间避免中断干扰。
- 校验和必查:不校验可能拿到错误数据。
- 起始拉低时间要够(≥18ms),太短从机不响应。
- 采样间隔 ≥ 1s,否则返回上一次或失败;例程两处
delay_ms(1000)不能删。 - DHT11 精度低(湿度 ±5%RH,温度 ±2℃),要求高换 DHT22/AM2302(协议相同,分辨率更高)。
- 手绘字模 → 汉字上下颠倒:本屏取模约定是「纵向8点下高位」——16×16 字 = 上半页 16 字节 + 下半页 16 字节,每字节 bit0 是页内最上面一行(不是 bit7)。写反整个字上下镜像。别手绘,用取模软件设置对了一次成型(可拿原库正常字反推验证)。
- 改了 .h 字库,编译"没变化":Keil 依赖跟踪没把
ASCII_8x16.h/CHS_16x16.h当依赖,增量编译(UV4 -b)根本不重编oled0561.c,pyocd 报identical ... programmed 0。改字库/头文件后一律全量重建(UV4.exe -r -j0)。 - pyocd 报 identical、写入 0 字节:即使编译正确也可能页比较误判 →
pyocd flash --erase chip --pack ...强制全片擦写,成功标志是日志明确写programmed N bytes。 - 宋体"度"字糊成一团:逐点渲染字模确认是字体固有缺陷——「广」的长撇 +「廿」两竖 = 三条竖线并排再交叉,宋体 1 像素细笔画小屏必然糊("湿/温"右边是「日」框所以清楚)。解法:换黑体(2 像素等粗笔画)或加大字号。
- printf 卡死(半主机):工程未勾 MicroLIB 时,
printf走 semihosting 把输出交给调试器,脱机运行卡死在 BKPT。解法 A(推荐):sprintf到缓冲区 +USART_SendData,不碰工程配置、跨电脑一致;解法 B:勾 MicroLIB 再重定向fputc。 - .md 文档改了"没反应":文件带只读属性,写入被静默拒绝。
(Get-Item xxx.md).IsReadOnly检查,Set-ItemProperty -Name IsReadOnly -Value $false解除。
#六、验证方法:从 hex 验尸
怀疑"屏上显示不对"时别靠肉眼猜,直接解析 hex 把烧进芯片的字库提出来渲染对比:
- 在
.map文件里找字库符号地址(如GB_16 0x08002cde Data 224 oled0561.o(.constdata)); - 解析 hex 文件(注意先处理 type 04 扩展线性地址记录,否则地址对不上、读出全是 0xFF);
- 按地址取字节,按 bit0=顶 的规则画成
#/.点阵图。
能 100% 确认"芯片里到底是什么字形",把"数据问题"和"显示问题"彻底分开——上面第 10 条(宋体度字)就是这样定性的。
#七、驱动代码(要点,HAL 风格伪代码)
c/* 微秒延时依赖 DWT 或 TIM */
void delay_us(uint32_t us);
uint8_t dht11_read(uint8_t *humid_h, uint8_t *temp_h)
{
uint8_t buf[5] = {0};
/* 1. 主机起始:拉低 18ms */
DHT11_OUTPUT();
HAL_GPIO_WritePin(DATA_PORT, DATA_PIN, 0);
delay_us(18000);
HAL_GPIO_WritePin(DATA_PORT, DATA_PIN, 1);
delay_us(30);
/* 2. 切输入,等从机 80us 低 + 80us 高 */
DHT11_INPUT();
if (wait_level(0, 100) || wait_level(1, 100)) return 1; /* 超时 */
/* 3. 读 40 bit */
for (int i = 0; i < 40; i++)
{
wait_level(0, 100); /* 等下降沿 */
delay_us(40); /* 采样点:40us 处判高低 */
buf[i/8] <<= 1;
if (HAL_GPIO_ReadPin(DATA_PORT, DATA_PIN)) buf[i/8] |= 1;
}
/* 4. 校验 */
if (buf[4] != (buf[0]+buf[1]+buf[2]+buf[3])) return 2;
*humid_h = buf[0]; *temp_h = buf[2];
return 0;
}
#八、调用示例
cuint8_t h, t;
if (dht11_read(&h, &t) == 0)
sprintf(buf, "RH=%d%% T=%dC\r\n", h, t), uart_send(buf); /* 别用 printf,见坑 11 */
HAL_Delay(1000); /* 间隔 ≥1s */
#九、相关链接
- OLED 字库与中文点阵:16×16 汉字取模——取模与字库机制详解
- 六轴姿态传感器(MPU6050,I2C)——同批实测的 I2C 显示改造模块
- 硬件 PWM 与电机控制原理——PA15 的另一个主人(舵机),两模块共用引脚
- 文章:STM32 低功耗三兄弟实测
#十、参考库/链接
- DHT11 数据手册(搜索 "DHT11 datasheet")
- 洋桃1号 A5 周围电路手册(温湿度传感器章节)
#11、更新日志
| 日期 | 类型 | 更新内容 |
|---|---|---|
| 2026-09-12 | 新增 | 首次建档:DHT11 单总线时序 + 踩坑 + 驱动要点 |
| 2026-09-20 | 实测更新 | 验证状态 ❌→✅(洋桃1号 2026-09-19 实测);接线改 PA15(补与舵机共用警告);新增"实测改造记录"(串口打印 / 单位美化借位 ° / 中文取模居中);踩坑清单并入 6 个实机坑(手绘字模颠倒、改 .h 未重编、pyocd identical、宋体度字、printf 半主机、只读属性);新增 hex 验尸验证法 |