DHT12温湿度传感器有两种工作方式, 一种是用I2C接口。 一种是单总线(也就是用一个GPIO口, DHT11只能用这种方式).
DHT12精度比DHT11的高,温湿度都有小数部分的。dht12的测量范围(-20 ~ 60), dht11(0 ~ 50)
应DHT12单总线的工作方式可以完全兼容DHT11,下面的图是从DHT11手册里抠出来的:
通过上图可得知,工作流程: 发开始信号 —> DHT12响应 —> DHT12发出40位数据
通过上图可得知。数据脚需接上拉。数据脚在发出开始信号阶段为输出, 开始信号完成后需配置为输入,让DHT12改变数据脚的电平来输出数据.
//
通过上图可获悉: DHT12输出数字0时,信号周期(以下降沿为参考)大约为76~78us, 高电平持续时间为26~28us. 输出数字1时,信号周期为120us, 其中高电平时间为70us.
///
DHT12收到开始信号后会输出响应信号,并输出40位数据。共输出41个下降沿,理论上可以捕捉41个下降沿中断,但在H3里测试时发现中断只捕捉到十多次,丢失了很多次应发生的中断。经查看H3手册,发现IO口的中断时钟源选择最低速的时钟,IO口的电平检查间隔时间过大.
只要把上图里的寄存器的时钟选择改为24MHz,即可捕捉到41次中断了.
驱动测试代码, test.c:
#include <linux/init.h>
#include <linux/module.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/ktime.h>
#include <asm/io.h>
#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");