DHT11-温湿度传感器
1、驱动模板
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include<mach/gpio-nrs.h>
#include<mach/gpio.h>
#include<linux/miscdevice.h>
#include<asm/ioctl.h>
#include<linux/interrupt.h>
#include<linux/irqreturn.h>
#include<linux/wait.h>
#include<linux/sched.h>
#include<linux/delay.h>#define DEV_NAME "dht11"
#define PIN_DHT11 S3C2410_GPF(6)static int open (struct inode * inode, struct file * file)
{printk("dht11 open ...\n");return 0;
}static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{printk("dht11 read ...\n");return 0;
}static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{return 0;
}static int close(struct inode *node,struct file *file)
{printk("dht11 close\n");return 0;
}static struct file_operations fops =
{.owner=THIS_MODULE,.open=open,.read=read,.write=write,
// .unlocked_ioctl=ioctl,.release=close
};static struct miscdevice misc=
{.minor=MISC_DYNAMIC_MINOR,.name=DEV_NAME,.fops=&fops
};static int __init dht11_init(void)
{int ret=0;ret=misc_register(&misc);if(ret<0)goto err_misc_register;printk("dht11_init...\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register faidht11\n");return ret;
}static void __exit dht11_exit(void)
{misc_deregister(&misc);printk("dht11_exit ...\n");
}module_init(dht11_init);
module_exit(dht11_exit);
MODULE_LICENSE("GPL");
2、基本概念
操作时序图
DHT11 采用单总线协议与单片机通信,单片机发送一次复位信号后,DHT11 从低功耗模式转换到高速模式,等待主机复位结束后,DHT11 发送响应信号,并拉高总线准备传输数据。一次完整的数据为 40bit,按照高位在前,低位在后的顺序传输。
数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和,一共 5 字节(40bit)数据。由于 DHT11 分辨率只能精确到个位,所以小数部分是数据全为 0。校验和为前 4 个字节数据相加,校验的目的是为了保证数据传输的准确性。
DHT11 只有在接收到开始信号后才触发一次温湿度采集,如果没有接收到主机发送复位信号,DHT11 不主动进行温湿度采集。当数据采集完毕且无开始信号后,DHT11 自动切换到低速模式。
初始化:主机开始发信号,至少拉低18ms低电平,然后拉高20~40us,等待响应
代码:
static void dht11_start(void)
{gpio_request(PIN_DHT11,"pin_dht11");gpio_direction_output(PIN_DHT11,DHT11_ON);msleep(40);gpio_set_value(PIN_DHT11,DHT11_OFF);mdelay(20);gpio_set_value(PIN_DHT11,DHT11_ON);udelay(30);gpio_direction_input(PIN_DHT11);
}
响应:首先应等待复位的高电平结束(如果没结束),等待80us的低电平结束从机,等待80us的高电平结束
代码:
static int dht11_response(void)
{int time =100;
//time=100,引脚为高电平1,一直等待,等待time为0时,就超时,如果在100以内,引脚为低电平,就不会超时
//等待引脚为低电平时,循环退出了,就往下走,且没有超时,就进入第二个循环while((time>0) && gpio_get_value(PIN_DHT11)){udelay(1);time--;}if(time<=0){printk("error\n");return -1;}
//此时电平为低电平,time=100,当time减为0时,就超时,但在100以内,变为高电平就不会超时time=100;while((time>0) && (!gpio_get_value(PIN_DHT11))){udelay(1);time--;}if(time<=0){printk("error2\n");return -1;}time=100;while((time>0) && gpio_get_value(PIN_DHT11)){udelay(1);time--;}if(time<=0){printk("error3\n");return -1;}return 0;
}
读数据:首先等待50us的低电平结束,然后等待35秒,如果电平是低,就代表是0,然后等待高电平结束,代表是1
static int get_bit(void)
{
//等待50us低电平结束int time = 100;while((time > 0) && (!gpio_get_value(PIN_DHT11))){udelay(1);time--;}if(time <= 0){printk("get_bit 1\n");return -1;}//等待35usudelay(35);//如果引脚电平是0,那么数据就是0if(0 == gpio_get_value(PIN_DHT11))return 0;
//再继续等待,直到低电平结束,数据是1time = 100;while((time > 0) && gpio_get_value(PIN_DHT11)){udelay(1);time--;}if(time <= 0){printk("get_bit 2\n");return -1;}return 1;
}
得到5个字节的数据:一个字节8个bit,所以循环8次,每次都左移一位
static int get_data(unsigned char *data)
{int i=0;int j=0;for(j=0;j<5;j++){data[j] = 0;for(i=0;i<8;i++){char tmp=0;data[j]<<=1;tmp=get_bit();if(tmp<0)return -1;data[j]|=tmp;}}return 0;
}
完整代码:
#if 1
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include<mach/gpio-nrs.h>
#include<mach/gpio.h>
#include<linux/miscdevice.h>
#include<asm/ioctl.h>
#include<linux/interrupt.h>
#include<linux/irqreturn.h>
#include<linux/wait.h>
#include<linux/sched.h>
#include<linux/delay.h>
#include <linux/workqueue.h>#define DEV_NAME "dht11"
#define PIN_DHT11 S3C2410_GPF(6)
#define DHT11_ON 1
#define DHT11_OFF 0static void dht11_start(void)
{gpio_request(PIN_DHT11,"pin_dht11");gpio_direction_output(PIN_DHT11,DHT11_ON);msleep(40);gpio_set_value(PIN_DHT11,DHT11_OFF);mdelay(20);gpio_set_value(PIN_DHT11,DHT11_ON);udelay(30);gpio_direction_input(PIN_DHT11);
}static int dht11_response(void)
{int time =100;while((time>0) && gpio_get_value(PIN_DHT11)){udelay(1);time--;}if(time<=0){printk("error\n");return -1;}time=100;while((time>0) && (!gpio_get_value(PIN_DHT11))){udelay(1);time--;}if(time<=0){printk("error2\n");return -1;}time=100;while((time>0) && gpio_get_value(PIN_DHT11)){udelay(1);time--;}if(time<=0){printk("error3\n");return -1;}return 0;
}static int get_bit(void)
{int time = 100;while((time > 0) && (!gpio_get_value(PIN_DHT11))){udelay(1);time--;}if(time <= 0){printk("get_bit 1\n");return -1;}udelay(35);if(0 == gpio_get_value(PIN_DHT11))return 0;time = 100;while((time > 0) && gpio_get_value(PIN_DHT11)){udelay(1);time--;}if(time <= 0){printk("get_bit 2\n");return -1;}return 1;
}static int get_data(unsigned char *data)
{int i=0;int j=0;for(j=0;j<5;j++){data[j] = 0;for(i=0;i<8;i++){char tmp=0;data[j]<<=1;tmp=get_bit();if(tmp<0)return -1;data[j]|=tmp;}}return 0;
}static int open (struct inode * inode, struct file * file)
{printk("dht11 open ...\n");return 0;
}static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{int ret=0;unsigned char data[5]={0};dht11_start();ret=dht11_response();if(ret<0)return -1;ret=get_data(data);if(ret<0)return -1;copy_to_user(buf,data,sizeof(data));printk("dht11 read ...\n");return sizeof(data);
}static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{return 0;
}static int close(struct inode *node,struct file *file)
{printk("dht11 close\n");return 0;
}//static dev_t dev_num;
static struct file_operations fops =
{.owner=THIS_MODULE,.open=open,.read=read,.write=write,
// .unlocked_ioctl=ioctl,.release=close
};static struct miscdevice misc=
{.minor=MISC_DYNAMIC_MINOR,.name=DEV_NAME,.fops=&fops
};static int __init dht11_init(void)
{int ret=0;ret=misc_register(&misc);if(ret<0)goto err_misc_register;printk("dht11_init...\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register faidht11\n");return ret;
}static void __exit dht11_exit(void)
{misc_deregister(&misc);printk("dht11_exit ...\n");
}module_init(dht11_init);
module_exit(dht11_exit);
MODULE_LICENSE("GPL");