这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 过程贴-实现DHT22的驱动和应用

共1条 1/1 1 跳转至

过程贴-实现DHT22的驱动和应用

菜鸟
2026-05-26 16:30:53     打赏

驱动程序

#define DT_DRV_COMPAT aosong_dht22

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/device.h>
#include <zephyr/sys/printk.h>


#define DHT22_RST_LOW_DELAY_US   18000
#define DHT22_RST_HIGH_DELAY_US  40
#define DHT22_BIT_DELAY_US       28
#define DHT22_RETRY_MAX          200

struct dht22_config {
    struct gpio_dt_spec gpio;
};

struct dht22_data {
    float temp;
    float humi;
};

static void dht22_set_pin_output(const struct gpio_dt_spec *gpio)
{    gpio_pin_configure_dt(gpio, GPIO_OUTPUT);
}

static void dht22_set_pin_input(const struct gpio_dt_spec *gpio)
{
    gpio_pin_configure_dt(gpio, GPIO_INPUT);
}

static void dht22_idle(const struct gpio_dt_spec *gpio)
{
    dht22_set_pin_output(gpio);
    gpio_pin_set_dt(gpio, 1);
    k_busy_wait(1000);
}

static void dht22_reset(const struct gpio_dt_spec *gpio)
{
    dht22_idle(gpio);
    dht22_set_pin_output(gpio);
    gpio_pin_set_dt(gpio, 0);
    k_busy_wait(DHT22_RST_LOW_DELAY_US);
    gpio_pin_set_dt(gpio, 1);
    k_busy_wait(DHT22_RST_HIGH_DELAY_US);
}

static uint8_t dht22_check_ack(const struct gpio_dt_spec *gpio)
{
    uint8_t retry = 0;
    dht22_set_pin_input(gpio);

    while (gpio_pin_get_dt(gpio) && retry < DHT22_RETRY_MAX) {
        retry++;
        k_busy_wait(1);
    }
    if (retry >= DHT22_RETRY_MAX) return 1;

    retry = 0;
    while (!gpio_pin_get_dt(gpio) && retry < DHT22_RETRY_MAX) {
        retry++;
        k_busy_wait(1);
    }
    if (retry >= DHT22_RETRY_MAX) return 1;

    return 0;
}

static uint8_t dht22_read_bit(const struct gpio_dt_spec *gpio)
{
    uint8_t retry = 0;

    while (gpio_pin_get_dt(gpio) && retry < DHT22_RETRY_MAX) {
        retry++;
        k_busy_wait(1);
    }
    retry = 0;

    while (!gpio_pin_get_dt(gpio) && retry < DHT22_RETRY_MAX) {
        retry++;
        k_busy_wait(1);
    }
    k_busy_wait(DHT22_BIT_DELAY_US);

    return gpio_pin_get_dt(gpio) ? 1 : 0;
}

static uint8_t dht22_read_byte(const struct gpio_dt_spec *gpio)
{
    uint8_t byte_val = 0;
    for (int i = 0; i < 8; i++) {
        byte_val <<= 1;
        byte_val |= dht22_read_bit(gpio);
    }
    return byte_val;
}

static int dht22_read(const struct device *dev)
{
    const struct dht22_config *cfg = dev->config;
    struct dht22_data *data = dev->data;
    uint8_t buf[5] = {0};

    dht22_reset(&cfg->gpio);
    if (dht22_check_ack(&cfg->gpio) != 0) {
        return -EIO;
    }

    for (int i = 0; i < 5; i++) {
        buf[i] = dht22_read_byte(&cfg->gpio);
    }

    data->humi = (float)((buf[0] << 8) + buf[1]) / 10.0f;
    data->temp = (buf[2] & 0x80) ? 
        -1.0f * (float)(((buf[2] & 0x7F) << 8) + buf[3]) / 10.0f :
        (float)((buf[2] << 8) + buf[3]) / 10.0f;

    return 0;
}

static int dht22_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
    ARG_UNUSED(chan);
    return dht22_read(dev);
}

static int dht22_channel_get(const struct device *dev,
                 enum sensor_channel chan,
                 struct sensor_value *val)
{
    struct dht22_data *data = dev->data;

    if (chan == SENSOR_CHAN_HUMIDITY) {
        val->val1 = (int32_t)data->humi;
        val->val2 = (int32_t)(data->humi * 100000) % 100000;
    } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
        val->val1 = (int32_t)data->temp;
        val->val2 = (int32_t)(data->temp * 100000) % 100000;
    }
    return 0;
}

static const struct sensor_driver_api dht22_api = {
    .sample_fetch = dht22_sample_fetch,
    .channel_get = dht22_channel_get,
};

static int dht22_init(const struct device *dev)
{
    const struct dht22_config *cfg = dev->config;
    if (!device_is_ready(cfg->gpio.port)) return -ENODEV;
    dht22_idle(&cfg->gpio);
    return 0;
}

#define DHT22_INIT(inst) 
    static struct dht22_data data_##inst; 
    static struct dht22_config config_##inst = { 
        .gpio = GPIO_DT_SPEC_INST_GET(inst, gpios), 
    }; 
    DEVICE_DT_INST_DEFINE(inst, 
                  dht22_init, 
                  NULL, 
                  &data_##inst, 
                  &config_##inst, 
                  POST_KERNEL, 
                  CONFIG_SENSOR_INIT_PRIORITY, 
                  &dht22_api);

DT_INST_FOREACH_STATUS_OKAY(DHT22_INIT)

这里我重点说一下这个DEVICE_DT_INST_DEFINE宏,这个宏可以说是Zephyr区别于其他RTOS的特色点所在。

这个宏注册设备进内核,注册完后:内核才能找到它,应用能打开它,才能读取到温湿度。

DEVICE_DT_INST_DEFINE(
    inst,           // 设备编号
    dht22_init,     // 初始化函数
    NULL,           // 电源管理(不用)
    &data_##inst,   // 该设备的数据区
    &config_##inst, // 该设备的配置区
    POST_KERNEL,    // 启动阶段
    CONFIG_SENSOR_INIT_PRIORITY, // 优先级
    &dht22_api      // 驱动API);

同时呢这个宏DT_INST_FOREACH_STATUS_OKAY(DHT22_INIT),遍历设备树中所有 status = "okay" 且 compatible 匹配的 DHT22 节点,逐个调用 DHT22_INIT (inst)。

下面就是设备树代码

/ {
	sensors {
		dht22: dht22 {
			compatible = "aosong,dht22";
			gpios = <&gpioc 1 GPIO_ACTIVE_HIGH>;
			status = "okay";
		};
	};
};

然后就是应用层代码本质就是:找到设备 → 读取数据 → 打印结果

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/printk.h>

#define DHT22_NODE DT_INST(0, aosong_dht22)
const struct device *dht22 = DEVICE_DT_GET(DHT22_NODE);

int main(void)
{
	struct sensor_value temp, humi;

	printk("*** Booting Zephyr OS build v4.2.0 ***n");
	printk("DHT22 设备初始化成功n");

	while (1) {
		int ret = sensor_sample_fetch(dht22);
		if (ret == 0) {
			sensor_channel_get(dht22, SENSOR_CHAN_AMBIENT_TEMP, &temp);
			sensor_channel_get(dht22, SENSOR_CHAN_HUMIDITY, &humi);

			printk("温度: %d.%d°C | 湿度: %d.%d%%RHn",
			       temp.val1, temp.val2 / 100000,
			       humi.val1, humi.val2 / 100000);
		}
		else {
			printk("读取失败,错误码: %dn", ret);
		}

		k_sleep(K_SECONDS(2));
	}
}

1最关键:找到设备树里的 DHT22

#define DHT22_NODE DT_INST(0, aosong_dht22)

2. 根据设备节点,获取设备指针

const struct device *dht22 = DEVICE_DT_GET(DHT22_NODE);

拿到驱动里 DEVICE_DT_INST_DEFINE 注册进内核的设备

实际的读取到的数据图片如下
image.pngimage.png





关键词: 嵌入式     WSL     驱动    

共1条 1/1 1 跳转至

回复

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