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;
}
//等待35us
udelay(35);
//如果引脚电平是0,那么数据就是0
if(0 == gpio_get_value(PIN_DHT11))
return 0;
//再继续等待,直到低电平结束,数据是1
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;
}
得到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 0
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);
}
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");