智能家居温湿度传感器驱动程序:
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℃
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;
}