34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题
2017-06-19 11:50
441 查看
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:
$(".MathJax").remove();
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");
$(".MathJax").remove();
相关文章推荐
- 关于Linux下I2C驱动的Probe方式没有自动生成i2c_client且没有自动调用i2c_driver的.probe指向的函数的问题解决
- 解决Linux网络问题,Linux安装网卡驱动(转:http://www.158558.cn/jianzhanchangshi/2010-04-16/33.html)
- fsck解决Linux数据丢失问题
- Linux本地采用字符界面的方式登录不成功--问题已解决
- linux升级笔记,ATI闭源显卡驱动,解决发热问题
- fsck解决Linux数据丢失问题
- 如何解决linux的root密码丢失问题
- Linux字符设备驱动-globalmem驱动编译加载遇到的问题及解决办法
- PL2303在ARM Linux下驱动的问题及解决方法
- 解决linux中flash掉电丢失数据问题
- ARM-Linux驱动--ADC驱动(中断方式)
- linux随笔 centos 6.2 出现repair filessystem 问题解决方式
- linux2.6.24下usb驱动完成情况及问题解决
- Linux2.6键盘驱动汇总:中断方式驱动/扫描方式驱动
- linux2.6.22下usb驱动完成情况及问题解决
- linux下出现的问题、解决方式总结【持续更新】
- 解决linux的root密码丢失问题(附图说明)
- high definition audio uaa总线驱动 问号解决问题
- Linux-2.6.32 下 块设备驱动的编写 与 相关问题解决
- 解决linux下由于驱动问题引起的RTL8111/8168B网卡下速度慢的问题