Linux下DHT11驱动编程,以及测试程序
来源:互联网 发布:python canny边缘检测 编辑:程序博客网 时间:2024/06/05 18:17
今天搞了一下DHT11的驱动编程,嘿嘿,分享给大家。
官方文档的时序图以及介绍如下:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据
+8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高 。
总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态.
然后还有一点要注意,就是两次读取时间要间隔至少1秒:
基本知识说完了,下面直接上一个完整的驱动程序(因为时间有限,就不细讲了):
#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/device.h>#include <linux/cdev.h>#include <linux/delay.h>#include <mach/gpio.h>#include <asm-generic/uaccess.h>#include <asm/io.h>#define DHT_MAJOR 0typedef struct{uint8_t humi_int; //湿度的整数部分uint8_t humi_deci; //湿度的小数部分uint8_t temp_int; //温度的整数部分uint8_t temp_deci; //温度的小数部分uint8_t check_sum; //校验和 } DHT11_Data_TypeDef;struct s5pv210_dht11{dev_t devno;struct cdev *cdev;struct class *cls;int value;};struct s5pv210_dht11 *dht_dev;DHT11_Data_TypeDef DHT11_Data;volatile unsigned long *GPH3_CONF;volatile unsigned long *GPH3_DAT;//从DHT11读取1byte数据,MSB先行uint8_t DHT11_ReadByte(void){uint8_t i, temp=0;//gpio_request(S5PV210_GPH3(5), "DQ_IN");//gpio_direction_input(S5PV210_GPH3(5));for(i=0;i<8;i++) { /*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/while(gpio_get_value(S5PV210_GPH3(5)) == 0);/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”, *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时 */udelay(40); //延时x us 这个延时需要大于数据0持续的时间即可 if(gpio_get_value(S5PV210_GPH3(5)))/* x us后仍为高电平表示数据“1” */{/* 等待数据1的高电平结束 */while(gpio_get_value(S5PV210_GPH3(5)));temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行 }else // x us后为低电平表示数据“0”{ temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行}}//gpio_free(S5PV210_GPH3(5));return temp;}/** * 一次完整的数据传输为40bit,高位先出 * 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和的末8位 */uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data){gpio_request(S5PV210_GPH3(5), "DQ_OUT");/*主机拉低*/gpio_direction_output(S5PV210_GPH3(5), 0);/*延时18ms,(>=18ms)*/mdelay(18);/*总线拉高 主机延时30us*/gpio_direction_output(S5PV210_GPH3(5), 1);udelay(30); //延时30us,(20~40us)/*主机设为输入 判断从机响应信号*/ gpio_direction_input(S5PV210_GPH3(5));/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/ if(gpio_get_value(S5PV210_GPH3(5)) == 0) {/*轮询直到从机发出 的80us 低电平 响应信号结束*/ while(gpio_get_value(S5PV210_GPH3(5)) == 0);/*轮询直到从机发出的 80us 高电平 标置信号结束*/while(gpio_get_value(S5PV210_GPH3(5)));/*开始接收数据*/ DHT11_Data->humi_int= DHT11_ReadByte();DHT11_Data->humi_deci= DHT11_ReadByte();DHT11_Data->temp_int= DHT11_ReadByte();DHT11_Data->temp_deci= DHT11_ReadByte();DHT11_Data->check_sum= DHT11_ReadByte();/*读取结束,引脚改为输出模式,主机拉高*/gpio_direction_output(S5PV210_GPH3(5), 1);gpio_free(S5PV210_GPH3(5));/*检查读取的数据是否正确*///DHT11_Data->check_sum的正确的结果是温湿度总和的末8位,结构体也有定义check_sum为uint8_t类型if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)return 0;else return -1;}elsereturn -1;}int dht_open(struct inode *inode, struct file *filp){printk("--------%s---------\n",__func__);// 初始化IO,输出*GPH3_CONF &= ~(0xf << 20);*GPH3_DAT |= (0x1 << 20);return 0;}ssize_t dht_read(struct file *filp, char __user *buf, size_t count, loff_t *fops){printk("--------%s---------\n",__func__);/*调用DHT11_Read_TempAndHumidity读取温湿度,若成功则输出该信息*/if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == 0){//由于DHT11的温湿度小数部分属于保留的,所以在这里加不加都一样printk("\r\n read ok!\r\n\r\n humi: %d.%d RH ,temp: %d.%d C \r\n",\DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);copy_to_user(buf, &DHT11_Data, count);}elseprintk("Read DHT11 ERROR!\r\n");return count;}long dht_ioctl(struct file *filp, unsigned int cmd, unsigned long args){printk("--------%s---------\n",__func__);/*调用DHT11_Read_TempAndHumidity读取温湿度,若成功则输出该信息*/if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == 0){//由于DHT11的温湿度小数部分属于保留的,所以在这里加不加都一样printk("\r\n read ok!\r\n\r\n humi: %d.%d RH ,temp: %d.%d C \r\n",\DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);}else{printk("Read DHT11 ERROR!\r\n");}// 把用户空间传递过来的args地址后的整数转化为指针void __user *argp = (void __user *)args;switch(cmd){case 0: // 温度copy_to_user(argp, &DHT11_Data.temp_int, sizeof(DHT11_Data.temp_int));break;case 1:// 湿度copy_to_user(argp, &DHT11_Data.humi_int, sizeof(DHT11_Data.humi_int));break;default:break;}return 0;}int dht_close(struct inode *inode, struct file *filp){printk("--------%s---------\n",__func__);*GPH3_CONF &= ~(0xf << 20);return 0;}const struct file_operations dht_fops = {.open = dht_open,.read = dht_read,.unlocked_ioctl = dht_ioctl,.release = dht_close,};static void __exit dht11_exit(void){printk("--------%s---------\n",__func__);//iounmap(0xE0200C60);device_destroy(dht_dev->cls, dht_dev->devno);class_destroy(dht_dev->cls);cdev_del(dht_dev->cdev);unregister_chrdev_region(dht_dev->devno, 1);kfree(dht_dev);}// 字符设备模块加载函数static int __init dht11_init(void){printk("--------%s---------\n",__func__);int ret = -1;// 分配一个全局的设备对象dht_dev = kzalloc(sizeof(struct s5pv210_dht11), GFP_KERNEL);if(NULL == dht_dev){printk("kzalloc failed !\n");return -ENOMEM;}// 申请设备号if(DHT_MAJOR){dht_dev->devno = MKDEV(DHT_MAJOR, 0);ret = register_chrdev_region(dht_dev->devno, 1, "DHT11_drv");}else {// 动态申请ret = alloc_chrdev_region(&dht_dev->devno, 16, 1, "DHT11_drv");}if(ret < 0){printk("register failed !\n");ret = -EINVAL;goto err;}// 分配一个cdevdht_dev->cdev = cdev_alloc();// 初始化cdevcdev_init(dht_dev->cdev, &dht_fops);// 注册cdevcdev_add(dht_dev->cdev, dht_dev->devno, 1);// 创建设备节点dht_dev->cls = class_create(THIS_MODULE, "dht_cls");device_create(dht_dev->cls, NULL, dht_dev->devno, NULL, "dht1");// 硬件初始化GPH3_CONF = ioremap(0xE0200C60, 8);GPH3_DAT = GPH3_CONF + 1;return 0;err:dht11_exit();return ret;}module_init(dht11_init);module_exit(dht11_exit);MODULE_LICENSE("GPL");
以上就是完整的驱动程序,下面在发一个测试程序:
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <stdint.h>struct DHT_structure{ uint8_t humi_int; uint8_t humi_deci; uint8_t temp_int; uint8_t temp_deci; uint8_t check_sum;};struct DHT_structure DHT11_data;int main(void){int ret = -1, fd = -1;fd = open("/dev/dht1", O_RDWR);if(fd < 0){ perror("open failed !\n"); exit(1);}bzero(&DHT11_data, sizeof(DHT11_data));while(1){#if 0 ret = read(fd, &DHT11_data, sizeof(DHT11_data)); if(ret < 0){perror("read failed !\n");exit(1); }#else#if 1//注意这两条ioctl不要同一时间调用,因为同时调用就相当于读两次,而读取第二次至少需要间隔1sret = ioctl(fd,1,&DHT11_data.humi_int);#elseret = ioctl(fd,0,&DHT11_data.temp_int);#endif#endif printf("humi: %d.%d, temp: %d.%d\n",DHT11_data.humi_int,\ DHT11_data.humi_deci,DHT11_data.temp_int,DHT11_data.temp_deci); sleep(1);}if(close(fd) < 0){ perror("close failed !\n"); exit(1);}return 0;}
就这样吧,写作业去了,回见各位!
阅读全文
1 0
- Linux下DHT11驱动编程,以及测试程序
- tinyos学习笔记11--DHT11驱动及测试程序
- Linux下fl2440之led驱动编写以及测试
- Linux的温湿度传感器DHT11驱动
- 46 dht11/dht12 linux platform驱动实现
- linux下的spi驱动及测试程序移植开发
- [嵌入式Linux驱动]S5PV210的DHT11温湿度传感器Linux驱动
- Linux触摸屏驱动测试程序
- AM3354之DHT11气温湿度传感器驱动和测试
- LED驱动测试程序以及静态加载驱动过程
- Android DHT11驱动
- 树莓派驱动DHT11模块
- Linux: 输入设备驱动测试程序
- 2440 Linux按键驱动及测试程序
- linux按键驱动编写及测试程序
- s3c2440开发板Linux系统下eeprom驱动制作以及读写程序
- linux下服务程序测试
- linux下串口程序测试
- JS入门的小笔记
- Python学习笔记(4) -- (关键词:杨辉三角、生成器)
- Android内存优化(一)DVM和ART原理初探
- Hrbust-1316-移动 II(广度优先搜索 路径记录)
- c语言——关键字
- Linux下DHT11驱动编程,以及测试程序
- POJ 1780 Code 笔记
- linux进程管理与调度
- pads中怎么漏铜
- c#值类型和引用类型的区别
- 洛谷 P1011 车站
- Android怎么加速启动Activity
- div垂直居中
- 母亲