接上一篇开箱贴,今天正式开始调试。这次的目标是在 Zephyr RTOS 下驱动 DFR0067 (DHT11) 传感器,并跑通蓝牙广播。Zephyr 这套环境对新手来说门槛不低,针对读取DHT11温湿度数据,我把踩坑过程完整记录下来。
硬件层面,DHT11 温湿度传感器通过 ADC 引脚(ADC0_A0/ADC0_B0)与开发板通信,负责采集温湿度模拟信号;ESP32 则通过 UART(flexcomm2_lpuart2)与主控交互,借助 AT 指令实现 BLE 透传。硬件接线很简洁:FRDM-MCXN947 的 TX/RX 分别对接 ESP32 的 RX(GPIO16)、TX(GPIO17),LED0 用于运行状态指示,整体采用 3.3V 供电,兼顾低功耗需求。DHT11驱动是整个项目的数据采集基础,基于 Zephyr 的 ADC 子系统开发。为降低 MCU 运算开销,我全程采用整数运算,完全沿用官方转换公式,将采集到的 ADC 原始值先换算为电压,再转换为 0.1℃/0.1% 精度的温湿度数值。驱动封装为标准的初始化、采集、取值三段式接口,上层业务无需关心底层 ADC 配置细节。

我基于开发的工程是peripheral_hr

定义基本参数
/* DHT11 sensor on PTB4 */ #define DHT11_NODE DT_NODELABEL(gpiob) #define DHT11_PIN 4 static const struct device *dht11_dev; static struct k_mutex dht11_mutex;
设置us级的延时用于DHT11温湿度获取的延时
/* Simple delay using nop loops - avoids k_busy_wait overhead */
static inline void delay_us(uint32_t us)
{
for (volatile uint32_t i = 0; i < us * 8; i++) {
__asm__ volatile("nop");
}
}DHT11初始化和读取函数
static int dht11_init(void)
{
dht11_dev = DEVICE_DT_GET(DHT11_NODE);
if (!device_is_ready(dht11_dev)) {
printk("DHT11: GPIO device not ready\n");
return -ENODEV;
}
k_mutex_init(&dht11_mutex);
int ret = gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
if (ret < 0) {
printk("DHT11: config failed (err %d)\n", ret);
return ret;
}
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
k_sleep(K_MSEC(1000));
return 0;
}
static int dht11_read(int16_t *temp_x10, int16_t *hum_x10)
{
uint8_t data[5] = {0};
int ret = 0;
unsigned int irq_key = 0;
uint32_t w;
k_mutex_lock(&dht11_mutex, K_FOREVER);
/*
* Start: pull low 20ms, then release high 30us
*/
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
gpio_pin_set(dht11_dev, DHT11_PIN, 0);
k_sleep(K_MSEC(20));
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
delay_us(30);
/*
* Switch to input. DHT11 will respond within ~40us.
*/
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_INPUT);
irq_key = irq_lock();
/*
* Wait for DHT11 response: low ~80us, then high ~80us.
* Then DHT11 pulls low to start first data bit (50us low).
* We eat that first 50us low here so bit loop is clean.
*/
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 500) { printk("DHT11: no resp\n"); ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 0) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
/*
* Read 40 bits. Bit format:
* - 50us low
* - ~27us high = 0
* - ~70us high = 1
*
* After DHT11's 80us high response, the line falls for ~50us.
* That fall is the start of bit 0 byte 0. We already consumed
* the 80us high above, and the next edge we see will be the
* 50us low of bit 0. So our first loop action (wait for low end)
* correctly syncs to bit 0.
*/
for (int b = 0; b < 5; b++) {
uint8_t val = 0;
for (int i = 0; i < 8; i++) {
/* Wait for 50us low to end */
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 0) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
/* Wait 35us from rising edge. At this point:
* - bit 0: 27us pulse is over, pin is low
* - bit 1: 70us pulse still active, pin is high
*/
delay_us(35);
val <<= 1;
if (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
val |= 1;
/* Consume remainder of 70us high */
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 200) break;
delay_us(1);
}
}
}
data[b] = val;
}
irq_unlock(irq_key);
irq_key = 0;
/*
* Parse DHT11 data
*/
printk("DHT11 raw: %02x %02x %02x %02x %02x\n",
data[0], data[1], data[2], data[3], data[4]);
*hum_x10 = (int16_t)data[0] * 10 + (int16_t)data[1];
*temp_x10 = (int16_t)data[2] * 10 + (int16_t)data[3];
ret = 0;
out:
if (irq_key) {
irq_unlock(irq_key);
}
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
k_mutex_unlock(&dht11_mutex);
return ret;
}串口输出如下,输出包括原始数据和解析得到的温湿度数据

我要赚赏金
