34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题

DHT12温湿度传感器有两种工作方式, 一种是用I2C接口。 一种是单总线(也就是用一个GPIO口, DHT11只能用这种方式).

DHT12精度比DHT11的高,温湿度都有小数部分的。dht12的测量范围(-20 ~ 60), dht11(0 ~ 50)

34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题_第1张图片

应DHT12单总线的工作方式可以完全兼容DHT11,下面的图是从DHT11手册里抠出来的:
34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题_第2张图片
通过上图可得知,工作流程: 发开始信号 —> DHT12响应 —> DHT12发出40位数据
////////////

34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题_第3张图片
通过上图可得知。数据脚需接上拉。数据脚在发出开始信号阶段为输出, 开始信号完成后需配置为输入,让DHT12改变数据脚的电平来输出数据.
//////////////

34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题_第4张图片
通过上图可获悉: DHT12输出数字0时,信号周期(以下降沿为参考)大约为76~78us, 高电平持续时间为26~28us. 输出数字1时,信号周期为120us, 其中高电平时间为70us.
///////////////////////////////////////////////////////////////////////////////////////

DHT12收到开始信号后会输出响应信号,并输出40位数据。共输出41个下降沿,理论上可以捕捉41个下降沿中断,但在H3里测试时发现中断只捕捉到十多次,丢失了很多次应发生的中断。经查看H3手册,发现IO口的中断时钟源选择最低速的时钟,IO口的电平检查间隔时间过大.
34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题_第5张图片
只要把上图里的寄存器的时钟选择改为24MHz,即可捕捉到41次中断了.

驱动测试代码, test.c:


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BASE 0x01C20800
u8 *vaddr;

// dht12采用单总线方式, 接PA(9)
#define DHT12_IO  GPIOA(9)



int num = 0;
unsigned int times[40]; //40位数据
irqreturn_t irq_func(int irqno, void *arg)
{
    static long long prev;
    long long now = ktime_to_us(ktime_get());
    int i, j, tmp;

    if (0 == num)
        prev = now;
    else
    {
        times[num-1] = now-prev;
        prev = now;
    }
    num++;

    if (41 == num) //收完40位数据
    {
        for (i = 0; i < 5; i++) //第几个字节
        {
            tmp = 0;
            for (j = 0; j < 8; j++) //每字节8位
            {
                if (times[i*8+j] > 100)
                    tmp |= 1<<(7-j); //从高位开始存放
            }
            printk("%02d ", tmp);
        }
        printk("\n");
    }

    return IRQ_HANDLED;
}

static int __init test_init(void)
{
    int ret;

    //设置PA组的外部中断时钟源为24MHz
    vaddr = ioremap(BASE, SZ_1M);
    iowrite32(1, vaddr+0x218);

    ret = gpio_request(DHT12_IO, "mydht12");
    if (ret < 0)
        goto err0;

    //发出开始信号, 先配置数据脚为输出
    gpio_direction_output(DHT12_IO, 0);
    msleep(30); //至少保持低电平18ms
    gpio_direction_output(DHT12_IO, 1);
    udelay(30); //保持高电平30us

    gpio_direction_input(DHT12_IO);
    if (gpio_get_value(DHT12_IO) && (gpio_get_value(DHT12_IO)))
    {
        printk("no dht12 ack\n");
        ret = -ENODEV;
        goto err1;
    }
    // ack got;
    ret = request_irq(gpio_to_irq(DHT12_IO), irq_func, IRQF_TRIGGER_FALLING, "mydht12", NULL);
    if (ret < 0)
        goto err2;  

    return 0;
err2:

err1:
    gpio_free(DHT12_IO);
err0:
    iounmap(vaddr);
    return ret;
}

static void __exit test_exit(void)
{
    gpio_free(DHT12_IO);
    free_irq(gpio_to_irq(DHT12_IO), NULL);
    iounmap(vaddr);
}

module_init(test_init);
module_exit(test_exit);

MODULE_LICENSE("GPL");

你可能感兴趣的:(OrangePi,H3,Linux设备驱动开发)