DHT11 是奥松电子(Aosong)推出的数字温湿度传感器,采用单总线(Single-Wire)协议通信,数据线仅需一根 GPIO + 一个上拉电阻。Zephyr RTOS 在 drivers/sensor/aosong/dht/ 中内置了完整驱动,兼容 DHT11 和 DHT22。
本次基于 NXP FRDM-MCXW71 开发板(SoC: MCXW716C, Cortex-M33F),将 Zephyr 原厂 DHT 驱动集成到 blinky 工程中,实现每 2 秒读取一次温湿度数据并通过串口打印。
2. 硬件接线
| VCC | 3.3V | 供电 |
| DATA | PTA19(GPIOA Pin 19) | 数据线,需 4.7kΩ~10kΩ 上拉至 VCC |
| GND | GND | 共地 |
⚠️ 注意:PTA19 在开发板默认配置中与 TPM0_CH2(PWM 输出)复用,必须通过 device tree overlay 禁用 TPM0,否则引脚无法工作在 GPIO 模式。
3. Device Tree Overlay
文件路径:blinky/boards/frdm_mcxw71.overlay
/ {
aliases {
dht0 = &dht11;
};
dht11: dht11 {
compatible = "aosong,dht"; /* 绑定到 DHT 驱动 */
dio-gpios = <&gpioa 19 GPIO_ACTIVE_LOW>;
status = "okay";
};
};
&gpioa {
status = "okay"; /* 启用 GPIOA 端口 */
};
&tpm0 {
status = "disabled"; /* 释放 PTA19 的 PWM 复用 */
};
关键点:
compatible = "aosong,dht" — 匹配驱动中的 DT_DRV_COMPAT aosong_dht
GPIO_ACTIVE_LOW — DHT 驱动通过逻辑电平反相来适配单总线协议
禁用 &tpm0 解决引脚复用冲突
4. Kconfig 配置
文件路径:blinky/prj.conf
CONFIG_GPIO=y # GPIO 子系统
CONFIG_SENSOR=y # Zephyr 传感器框架
CONFIG_DHT=y # DHT 驱动(依赖 DT_HAS_AOSONG_DHT_ENABLED)
CONFIG_PRINTK=y # 内核日志输出
驱动本身的 Kconfig 层级:
CONFIG_DHT (menuconfig)
├── depends on DT_HAS_AOSONG_DHT_ENABLED ← 由 overlay 中的 compatible 自动满足
├── depends on GPIO
└── CONFIG_DHT_LOCK_IRQS (可选)
└── 读取时锁中断,提高成功率,但影响蓝牙等实时任务
5. 驱动分层架构

应用层通过 Zephyr Sensor 框架统一接口访问,无需关心单总线协议细节
驱动底层用 k_cycle_get_32() 硬件 Cycle 计数器实现微秒级脉冲测量
6. DHT11 单总线通信协议
DHT11 采用单总线协议,MCU 作为主机发起通信,传感器应答后返回 40 位数据。

校验:(Byte0+Byte1+Byte2+Byte3) & 0xFF == Byte4。DHT11 小数位恒为 0。
7. 核心流程详解
7.1 驱动初始化流程
初始化仅做 GPIO 上电准备,不主动与传感器通信。真正的通信在 sensor_sample_fetch() 时按需触发。
7.2 数据采集流程 — dht_sample_fetch()

自适应阈值:从 40 个脉冲中动态计算 (max_duration + min_duration) / 2,避免硬编码时序阈值,跨 MCU 兼容性好。
8. 应用层 main.c
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#define SLEEP_TIME_MS 2000
int main(void)
{
/* 1. 获取 DHT11 设备句柄 */
const struct device *const dht = DEVICE_DT_GET_OR_NULL(DT_ALIAS(dht0));
if (!device_is_ready(dht)) {
printk("DHT11: device not readyn");
return 0;
}
while (1) {
/* 2. 触发一次采样(阻塞,约 25ms) */
int ret = sensor_sample_fetch(dht);
if (ret != 0) {
printk("DHT11: fetch failed: %dn", ret);
} else {
struct sensor_value temp, humidity;
/* 3. 从驱动缓存读取解析后的值 */
sensor_channel_get(dht, SENSOR_CHAN_AMBIENT_TEMP, &temp);
sensor_channel_get(dht, SENSOR_CHAN_HUMIDITY, &humidity);
printk("DHT11: Temperature: %d.%d C, Humidity: %d.%d %%RHn",
temp.val1, temp.val2 / 100000,
humidity.val1, humidity.val2 / 100000);
}
k_msleep(SLEEP_TIME_MS); /* DHT11 要求 ≥1s 采样间隔 */
}
return 0;
}
应用层调用链路(非 RTIO 路径):
main()
→ sensor_sample_fetch(dht) // Zephyr sensor 框架
→ dht_sample_fetch() // DHT 驱动实现,bit-bang 单总线通信
→ sensor_channel_get(dht, ...) // Zephyr sensor 框架
→ dht_channel_get() // 解析 sample[] 为 sensor_value
9. 结果展示
10. 总结
Zephyr 的 DHT 驱动设计精巧:
自适应阈值替代硬编码时序判断,跨 MCU 兼容性好
单 GPIO + Cycle 计数器实现微秒级测量,无需专用定时器
Sensor 框架统一接口,应用层无需关心底层协议
Device Tree 与 Kconfig 解耦硬件描述与编译配置
集成到 FRDM-MCXW71 时,唯一需注意的硬件细节是 PTA19 引脚复用冲突

我要赚赏金
