[嵌入式Linux驱动]S5PV210的DHT11温湿度传感器Linux驱动

智能家居温湿度传感器驱动程序:
1. 本驱动使用platform模型进行设计,分为Temp_And_Humidity_device和Temp_And_Humidity_driver两个文件

2. 注册杂项设备(misc),主设备号固定是10(misc),从设备号由系统自动分配,加载成功后使用lsmod可以看到:
    Temp_And_Humidity_device
    Temp_And_Humidity_driver

3. 加载driver驱动模块之后自动对gpio进行初始化,初始化成功会输出:
 [   36.605575] entering Temp_And_Humidity_driver_init
 [   36.605702] entering Temp_And_Humidity_dirver_probe
 [   36.609147] Temp_And_Humidity_dirver_probe: gpio init finished!!!    //GPIO初始化成功
 
4. 本驱动注册成功后生成 /dev/smarthome_temphumi_sensor_control 节点

5. 对 smarthome_lightcontrol 设备节点的操作主要有:
   1)打开操作open
   2)关闭操作close
   3)读操作read,操作方法:
  
 声明一个结构体:  
 struct DHT11_Data{
         unsigned short humi_int;  //8bit湿度整数数据
         unsigned short humi_float;  //8bit湿度小数数据
         unsigned short temp_int;  //8bit温度整数数据
         unsigned short temp_float;  //8bit温度小数数据
         unsigned short check_sum;  //8bit校验和
  
  //校验和 = (8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据)(取低8位)
  //驱动程序里面已对数据进行校验处理,处理结果会以错误类型代码的形式发送给用户空间应用程序。
 
        unsigned short error_code;  //错误类型代码
 };

 然后使用read函数读取驱动,将结构体的地址作为缓冲区的首地址。
 
 读取完成后,请先对结构体里面的错误代码进行检查。以下是错误代码表:
 
 #define DHT_NO_ERROR      0  //没有错误,可以直接使用结构体里面的数据
 #define DHT_ERROR_NO_RESPOND    1  //温湿度传感器没有响应,数据异常
 #define DHT_ERROR_RESPOND_TIMEOUT   2  //温湿度传感器响应超时,数据异常
 #define DHT_ERROR_AFTERRESPOND_TIMEOUT  3  //温湿度传感器后响应超时,数据异常
 #define DHT_ERROR_PROBEBIT_TIMEOUT   4  //温湿度传感器前导信号异常,数据异常
 #define DHT_ERROR_DATABIT_TIMEOUT   5  //温湿度传感器数值传送异常,数据异常
 #define DHT_ERROR_CHECK_SUM_FAIL   10  //温湿度传感器数据校验失败,数据异常
 
 请不要在数据异常情况下使用结构体的数据。
 
 读操作所用总时间约为2秒(由传感器本身决定)。由于数据有时会波动,请酌情考虑在应用程序中使用算法去抖。
 
 其它详见例程。
 
6. 在打开驱动文件后,会对设备驱动使用互斥锁进行上锁操作。避免其他进程或线程同时访问驱动文件,打乱通信时序。直到关闭驱动文件才解锁。

7. 重构了整个室内机驱动的框架
         模块单独调试时请将driver文件里面的SINGLE_MODULE宏修改为1(独立申请内存)
         整体调试时请将driver文件里面的SINGLE_MODULE宏修改为0(内存由框架代码统一申请)
 
8. 开启模块调试信息请将driver文件里面的DEBUG宏修改为1,关闭设为0。

9. 温湿度传感器测量范围(以25摄氏度环境下测量为准)
   湿度:20%RH  ---  90%RH
   温度:0℃  ---  50℃


[嵌入式Linux驱动]S5PV210的DHT11温湿度传感器Linux驱动_第1张图片


DHT11工作时序图



Temp_And_Humidity_device.c

#include 

#include 
#include 

#include 

static int ret=0;

#define S5PV210_GPH_BASE 0xe0200c00			//read the s5pv210 datasheet!
#define GPH_SIZE 0x6c


void Temp_And_Humidity_device_release(struct device * pdev);	//important!

static struct resource Temp_And_Humidity_resource[]={

	[0] = {
		.start = S5PV210_GPH_BASE,
		.end   = S5PV210_GPH_BASE + GPH_SIZE,
		.name  = "GPH_BASE",
		.flags = IORESOURCE_MEM,
	},
};

struct platform_device Temp_And_Humidity_device={
	.name = "Temp_And_Humidity_drv",
	.id = -1,
	.dev={
		.release=Temp_And_Humidity_device_release,
	},
	.num_resources = ARRAY_SIZE(Temp_And_Humidity_resource),
	.resource = Temp_And_Humidity_resource,
};


void Temp_And_Humidity_device_release(struct device * pdev)
{
	printk("entering %s\n",__FUNCTION__);
}


static int __init Temp_And_Humidity_device_init(void)
{
	printk("entering %s\n",__FUNCTION__);

	ret=platform_device_register(&Temp_And_Humidity_device);

	if(ret<0){
		printk("%s: platform_device_register failed! \n",__FUNCTION__);
		return ret;
	}

	return 0;
}


static void __exit Temp_And_Humidity_device_exit(void)
{
	printk("entering %s\n",__FUNCTION__);

	platform_device_unregister(&Temp_And_Humidity_device);
}


module_init(Temp_And_Humidity_device_init);
module_exit(Temp_And_Humidity_device_exit);

MODULE_AUTHOR("kinyanderson");
MODULE_DESCRIPTION("Temp_And_Humidity_device,use for controlling the Temp_And_Humidity_Sensor");
MODULE_LICENSE("GPL");

Temp_And_Humidity_driver.c
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DEBUG 1
#define SINGLE_MODULE 1


/*** macro use for gpio configuring ***/

#define SET_GPH3_0_OUTPUT(n) do{		\
	n =ioread32(GPH3_BASE+0);		\
	n &= ~(0xf<<0);				\
	n |= (0x1<<0);				\
	iowrite32(n,GPH3_BASE+0); 		\
}while(0)

#define SET_GPH3_0_INPUT(n) do{			\
	n =ioread32(GPH3_BASE+0);		\
	n &= ~(0xf<<0);				\
	iowrite32(n,GPH3_BASE+0);	 	\
}while(0)


#define SET_GPH3_0_EINT24(n) do{		\
	n =ioread32(GPH3_BASE+0);		\
	n |= (0xf<<0);				\
	iowrite32(n,GPH3_BASE+0); 		\
}while(0)


#define SET_GPH3_0_HIGH_LEVEL(n) do{		\
	tmp =ioread32(GPH3_BASE+1);		\
	tmp  |= (0x1<<0);			\
	iowrite32(tmp,GPH3_BASE+1);		\
}while(0)


#define SET_GPH3_0_LOW_LEVEL(n) do{		\
	tmp =ioread32(GPH3_BASE+1);		\
	tmp  &= ~(0x1<<0);			\
	iowrite32(tmp,GPH3_BASE+1);		\
}while(0)


/*** The sensor's information, 这个根据DHT11的说明书设置 ***/
struct DHT11_Info{

	unsigned short sampling_interval;      /* DHT11的工作时间间隔 */
	unsigned short host_pull_down_time;
	unsigned short host_pull_up_time;
	unsigned short dht_respond_time;
	unsigned short dht_pull_up_time;
	unsigned short probe_bit_time;
	unsigned short data_bit_0_time;
	unsigned short data_bit_1_time;
};

static struct DHT11_Info dht11_info={
/* ms */
	.sampling_interval=1000,
	.host_pull_down_time=18,
/* us */
	.host_pull_up_time=40,
	.dht_respond_time=80,
	.dht_pull_up_time=80,
	.probe_bit_time  =50,
	.data_bit_0_time =28,
	.data_bit_1_time =70,
}; 

#define DEVIATION_TIME 20			//us

/*** The sensor's data ***/

struct DHT11_Data{
	unsigned short humi_int;
	unsigned short humi_float;
	unsigned short temp_int;
	unsigned short temp_float;
	unsigned short check_sum;
	unsigned short error_code;
};


#define DHT_NO_ERROR				0
#define DHT_ERROR_NO_RESPOND			1
#define DHT_ERROR_RESPOND_TIMEOUT		2
#define DHT_ERROR_AFTERRESPOND_TIMEOUT	        3
#define DHT_ERROR_PROBEBIT_TIMEOUT		4
#define DHT_ERROR_DATABIT_TIMEOUT		5

#define DHT_ERROR_CHECK_SUM_FAIL		10

//静态全局变量,用于存放dht11的读数
static struct DHT11_Data dht11_data={

	.error_code=DHT_NO_ERROR,
};


/* Transfer timeout check,防止超时死循环,需要有退出机制 */
#define DHT_TIMEOUT_CHECK(err_code,time,check) do{		\												                \
	udelay(5);	                                        \
	check++;				                \												                \
	if(check>(time/5)){					\
		dht11_data.error_code=err_code;			\
		printk("The sensor transfer failed! Code:%d\n",err_code);             \
										                \
		do{										\
			ret = copy_to_user(buff,(void *)(&dht11_data),sizeof(dht11_data));	\
		}while(ret);									\
												\
		return -1;									\
	}											\
}while(0)


#define RECEIVE_DATA_FROM_SENSOR(value,bit_num,check) do{		\
									\
	value=0;							\
									\
	for(bit_num=7;bit_num>=0;bit_num--){				\
									\
		check=0;						\
									\
		do{ 							\
			tmp =ioread32(GPH3_BASE+1);			\
			tmp = (tmp>>0) & 0x1;			\
			DHT_TIMEOUT_CHECK(DHT_ERROR_PROBEBIT_TIMEOUT, dht11_info.probe_bit_time+DEVIATION_TIME,check);     \
											       \
		}while(!tmp);								       \
											       \
		check=0;								       \
											       \
		do{ 									  \
			tmp =ioread32(GPH3_BASE+1);					  \
			tmp = (tmp>>0) & 0x1;					  \
											  \
			DHT_TIMEOUT_CHECK(DHT_ERROR_DATABIT_TIMEOUT, dht11_info.data_bit_1_time+DEVIATION_TIME,check);	\
												\
		}while(tmp);									\
												\
		if(check>5 && check<=7)						        \
		     value &= ~(0x1<6 && check<15)				                \
		     value |= (0x1<>0) & 0x1;

		DHT_TIMEOUT_CHECK(DHT_ERROR_NO_RESPOND, dht11_info.host_pull_up_time+DEVIATION_TIME,check);
	}while(tmp);
	
	check=0;

	do{						//respond last about 80us
		tmp =ioread32(GPH3_BASE+1);
		tmp = (tmp>>0) & 0x1;

		DHT_TIMEOUT_CHECK(DHT_ERROR_RESPOND_TIMEOUT, dht11_info.dht_respond_time+DEVIATION_TIME,check);		
	}while(!tmp);

	check=0;

	do{					//high level after respond last about 80us
		tmp =ioread32(GPH3_BASE+1);
		tmp = (tmp>>0) & 0x1;

		DHT_TIMEOUT_CHECK(DHT_ERROR_AFTERRESPOND_TIMEOUT, dht11_info.dht_pull_up_time+DEVIATION_TIME,check);
	}while(tmp);

/* Starting to transfer the data */

	memset((void*)&dht11_data,0,sizeof(dht11_data));

	int i;
	unsigned short value;
	
/*8bit - 1*/
	RECEIVE_DATA_FROM_SENSOR(value,i,check);
	dht11_data.humi_int=value;

/*8bit - 2*/
	RECEIVE_DATA_FROM_SENSOR(value,i,check);
	dht11_data.humi_float=value;

/*8bit - 3*/
	RECEIVE_DATA_FROM_SENSOR(value,i,check);
	dht11_data.temp_int=value;

/*8bit - 4*/
	RECEIVE_DATA_FROM_SENSOR(value,i,check);
	dht11_data.temp_float=value;

/*8bit - 5*/
	RECEIVE_DATA_FROM_SENSOR(value,i,check);
	dht11_data.check_sum=value;

	printk("Receiving dht11 data completed! %s\n",__FUNCTION__);

        return 0;
}


ssize_t Temp_And_Humidity_driver_read (struct file *file_p,char __user *buff,size_t size,loff_t *offset)
{
	printk("entering %s\n",__FUNCTION__);

	msleep(dht11_info.sampling_interval);
	
        unsigned long flag;

        /* 防止内核调度抢占 */
        local_irq_save(flag);

        ReadDht11Data();

        local_irq_restore(flag);

	check=dht11_data.humi_int + dht11_data.humi_float + dht11_data.temp_int + dht11_data.temp_float;

	if( (unsigned short)(check&0xff) != dht11_data.check_sum){
		printk("Data checksum failed ! %s\n",__FUNCTION__);		
		dht11_data.error_code=DHT_ERROR_CHECK_SUM_FAIL;
	}

        int i;

	for(i=0;i<3;i++)
        {
		ret = copy_to_user(buff,(void *) &dht11_data,sizeof(dht11_data));

                if(0 == ret)
                   break;
        }
	return 0;	
}

int Temp_And_Humidity_driver_close (struct inode *inode_p, struct file *file_p)
{
	printk("entering %s\n",__FUNCTION__);
	
/* Unlocked */
	mutex_unlock(&Temp_And_Humi_mutex);
	
	return 0;
}


/*** driver_operation ****/

static int __devinit  Temp_And_Humidity_dirver_probe(struct platform_device * pdev)
{
	printk("entering %s\n",__FUNCTION__);

	struct resource * pcheck;

	platform_resource=platform_get_resource(pdev,IORESOURCE_MEM,0);

	if(NULL==platform_resource){
		printk("%s: platform_get_resource failed!\n",__FUNCTION__);	
		goto err1;
	}

#if SINGLE_MODULE
	pcheck=request_mem_region(platform_resource->start,
				  platform_resource->end - platform_resource->start + 1,
				  platform_resource->name);

	if(NULL==pcheck){
		printk("%s: request_mem_region failed!\n",__FUNCTION__);	
		goto err1;						//return device busy!
	}
#endif

	GPH_BASE=(unsigned long *)ioremap(platform_resource->start, platform_resource->end - platform_resource->start + 1);

#if DEBUG
	printk("%s: GPH_BASE is %p \n",__FUNCTION__,GPH_BASE);		

	printk("%s: GPH3_BASE is %p \n",__FUNCTION__,GPH3_BASE);	
#endif

	ret = misc_register(&Temp_And_Humidity_miscdev);

	if(ret<0){
		printk("%s: misc_register failed!\n",__FUNCTION__);	
		goto err2;
	}

	unsigned int tmp;
	
/* initing the gpio */

	//GPH3CON[0]	[3:0]=0001	0000-output	0001-input
	SET_GPH3_0_OUTPUT(tmp);

	//GPH3DAT[0]=0
	SET_GPH3_0_HIGH_LEVEL(tmp);
	
	printk("%s: gpio init finished!!!\n",__FUNCTION__);

/* initing the mutex */

	mutex_init(&Temp_And_Humi_mutex);

	return 0;

err2:
	iounmap(GPH_BASE);
	
#if SINGLE_MODULE
	release_mem_region(platform_resource->start, platform_resource->end - platform_resource->start + 1);
#endif

err1:
	return -EBUSY;	
}


static int __devexit  Temp_And_Humidity_driver_remove(struct platform_device * pdev)
{
	printk("entering %s\n",__FUNCTION__);

	mutex_destroy(&Temp_And_Humi_mutex);

	iounmap(GPH_BASE);
	
#if SINGLE_MODULE
	release_mem_region(platform_resource->start, platform_resource->end - platform_resource->start + 1);
#endif

	ret=misc_deregister(&Temp_And_Humidity_miscdev);

	if(ret){
		printk("%s:misc_deregister failed!\n",__FUNCTION__);
		return ret;
	}
	return 0;
}


static int __init  Temp_And_Humidity_driver_init(void)
{
	printk("entering %s\n",__FUNCTION__);

	ret=platform_driver_register(& Temp_And_Humidity_driver);

	if(ret<0){
		printk("%s: driver_register failed!\n",__FUNCTION__);
		return ret;
	}
	return 0;
}


static void __exit  Temp_And_Humidity_driver_exit(void)
{
	printk("entering %s\n",__FUNCTION__);
	platform_driver_unregister(& Temp_And_Humidity_driver);
}

module_init(Temp_And_Humidity_driver_init);
module_exit(Temp_And_Humidity_driver_exit);

MODULE_AUTHOR("kinyanderson");
MODULE_DESCRIPTION("Temp_And_Humidity_driver,use for controlling the Temp_And_Humidity sensor");
MODULE_LICENSE("GPL");

Makefile
obj-m +=  Temp_And_Humidity_device.o  Temp_And_Humidity_driver.o

KDIR := /home/kinyanderson/final_design/android-kernel-samsung-dev

modules:
	make modules -C $(KDIR) M=`pwd`
	arm-linux-gcc app.c -o app

clean:
	make modules clean -C $(KDIR) M=`pwd`


App程序
#include 
#include 
#include 
#include 

struct DHT11_Data{

	unsigned short humi_int;
	unsigned short humi_float;
	unsigned short temp_int;
	unsigned short temp_float;
	unsigned short check_sum;
	unsigned short error_code;
};

#define DHT_NO_ERROR				0
#define DHT_ERROR_NO_RESPOND			1
#define DHT_ERROR_RESPOND_TIMEOUT		2
#define DHT_ERROR_AFTERRESPOND_TIMEOUT	        3
#define DHT_ERROR_PROBEBIT_TIMEOUT		4
#define DHT_ERROR_DATABIT_TIMEOUT		5

#define DHT_ERROR_CHECK_SUM_FAIL		10


static struct DHT11_Data dht11_data;

int main(int argc,char **argv)
{
	int fd;
	int i=10;
	int ret;

	fd = open("/dev/smarthome_temphumi_sensor_control",O_RDWR);

	if(fd < 0){
		printf("can not open smarthome_temphumi_sensor_control!!!\n");
		return -1;
	}

	while(i--)
	{
		bzero(&dht11_data,sizeof(dht11_data));

		ret=read(fd,&dht11_data,sizeof(dht11_data));
		if(ret<0){
			printf("failed to read smarthome_temphumi_sensor_control!!!\n");
			close(fd);

			return -1;
		}

		if(dht11_data.error_code)
		{
			switch(dht11_data.error_code)
			{
				case DHT_ERROR_NO_RESPOND:
					printf("The error is DHT_ERROR_NO_RESPOND!\n");
					break;

				case DHT_ERROR_RESPOND_TIMEOUT:
					printf("The error is DHT_ERROR_RESPOND_TIMEOUT!\n");
					break;

				case DHT_ERROR_AFTERRESPOND_TIMEOUT:
					printf("The error is DHT_ERROR_NO_RESPOND!\n");
					break;

				case DHT_ERROR_PROBEBIT_TIMEOUT:
					printf("The error is DHT_ERROR_NO_RESPOND!\n");
					break;

				case DHT_ERROR_DATABIT_TIMEOUT:
					printf("The error is DHT_ERROR_DATABIT_TIMEOUT!\n");
					break;

				case DHT_ERROR_CHECK_SUM_FAIL:
					printf("The error is DHT_ERROR_CHECK_SUM_FAIL!\n");
					break;

				default:
					break;
			}

			continue;
		}

		printf("The current humidity is: %d.%d\n",dht11_data.humi_int,dht11_data.humi_float);
		printf("The current temperature is: %d.%d\n",dht11_data.temp_int,dht11_data.temp_float);	
		printf("The checksum is: %d\n\n",dht11_data.check_sum);	

		sleep(5);

	}

	close(fd);

	printf("the app finished!!!\n");
	return 0;
}




你可能感兴趣的:(嵌入式,ARM,C语言,C代码案例,Linux)