DHT11-温湿度传感器

发布于:2025-09-03 ⋅ 阅读:(24) ⋅ 点赞:(0)

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");


网站公告

今日签到

点亮在社区的每一天
去签到