这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【e起DIY】低功耗蓝牙温湿度计-过程贴

共2条 1/1 1 跳转至

【e起DIY】低功耗蓝牙温湿度计-过程贴

菜鸟
2026-06-29 14:12:15     打赏

接上一篇开箱贴,今天正式开始调试。这次的目标是在 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 配置细节。

image.png

我基于开发的工程是peripheral_hr

image.png

定义基本参数

/* 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;
}

串口输出如下,输出包括原始数据和解析得到的温湿度数据

image.png





专家
2026-06-30 08:03:30     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]