将DHT11移植到Linux系统上
2016-03-04 19:42
465 查看
由于项目需要,需要将DHT11移植到Linux。驱动程序如下
测试程序如下
#include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/serio.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <asm-generic/uaccess.h> #include <linux/spinlock.h> #include <linux/mutex.h> #define DEVICE_NAME "dht11" #define PIN S5PV210_GPH0(0) typedef unsigned char U8; unsigned char buf[6]; unsigned char check_flag; //spinlock_t lock=SPIN_LOCK_UNLOCKED; //spinlock_t lock=SPIN_LOCK_UNLOCKED; //DEFINE_SPINLOCK(lock); static DEFINE_MUTEX(mutex); int read_one_bit(void) //从io口中读一个字节 { gpio_direction_input(PIN); return gpio_get_value(PIN); } void gpio_out(int value) //将io口设置为输出,并设置电平 { gpio_direction_output(PIN,value); } unsigned char humidity_read_byte(void) { int i=0; int num; unsigned char flag=0; unsigned char data=0; for(num=0;num<8;num++) { i=0; while(!gpio_get_value(PIN)) { udelay(10); i++; if(i>10) break; } flag=0x0; udelay(28); if(gpio_get_value(PIN)) { flag=0x01; } i=0; while(gpio_get_value(PIN)) { udelay(10); i++; if(i>12) break; } data<<=1; data|=flag; } return data; } void humidity_read_data(void) { int i=0; gpio_out(0); mdelay(30); gpio_out(1); udelay(20); if(read_one_bit()== 0) { while(!gpio_get_value(PIN)) { udelay(5); i++; if(i>20) { printk("humidity_read_data %d err!\n",__LINE__); break; } } i=0; while(gpio_get_value(PIN)) { udelay(5); i++; if(i>20) { printk("humidity_read_data %d err!\n",__LINE__); break; } } for(i=0;i<5;i++) buf[i]=humidity_read_byte(); buf[5]=buf[0]+buf[1]+buf[2]+buf[3]; if(buf[4]==buf[5]) { check_flag=0xff; printk("humidity check pass\n"); printk("humidity=[%d],temp=[%d]\n",buf[0],buf[2]); } else { check_flag=0x0; printk("humidity check fail\n"); } } } static ssize_t humidiy_read(struct file *file, char __user *buffer, size_t size, loff_t *off) { int ret; local_irq_disable(); humidity_read_data(); local_irq_enable(); if(check_flag==0xff) { ret=copy_to_user(buffer,buf,sizeof(buf)); if(ret<0){ printk("copy to user err\n"); return -EAGAIN; } else return 0; } else return -EAGAIN; } static int humidiy_open(struct inode *inode, struct file *file) { printk("open in kernel\n"); return 0; } static int humidiy_release(struct inode *inode, struct file *file) { printk("humidity release\n"); return 0; } static struct file_operations humidity_dev_fops={ .owner = THIS_MODULE, .open = humidiy_open, .read = humidiy_read, .release = humidiy_release, }; static struct miscdevice humidity_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &humidity_dev_fops, }; static int __init humidity_dev_init(void) { int ret; ret = gpio_request(PIN , "humidity"); if (ret){ printk("%s: request GPIO %d for humidity failed, ret = %d\n", DEVICE_NAME,PIN , ret); return ret; } gpio_direction_output(PIN, 1); ret = misc_register(&humidity_dev); printk("humidity_dev_init\n"); return ret; } static void __exit humidity_dev_exit(void) { gpio_free(PIN); misc_deregister(&humidity_dev); } module_init(humidity_dev_init); module_exit(humidity_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("WWW")
测试程序如下
#include<stdio.h> #include<sys/types.h> int main() { int humidityfd; int ret; char buf[5]; unsigned char tempz = 0; unsigned char tempx = 0; unsigned char humidiyz = 0; unsigned char humidiyx = 0; humidityfd = open("/dev/humidity",0); if(humidityfd<0){ printf("/dev/humidiy open fail\n"); return 0; } while(1){ ret=read(humidityfd,buf,sizeof(buf)); if(ret<0) printf("read err!\n"); else{ humidiyz =buf[0]; humidiyx =buf[1]; tempz =buf[2] ; tempx =buf[3]; printf("humidity = %d.%d%%\n", humidiyz, humidiyx); printf("temp = %d.%d\n",tempz,tempx); } sleep(2); } close(humidityfd); return 0; }本想,这驱动调试起来应该简单的。但在调试到过程中,发现采集到的数据有时正确,有时错误,成功率约为50%。于是按照手册微调一下时序,并没有解决问题。网上查阅相关资料,发现都是用单片机来编程的。当程序本来就是以裸奔的思想跑的,为什么移植到Linux会出错呢?从dht11出来的信号都正常啊。误打误撞,使用local_irq_disable这个函数后,读出的数据都正常啦。local_irq_disable通过屏蔽中断标志位,从而禁止内核的抢占。我猜测是Linux是个多任务系统,该系统按照一定的算法(每隔一段时间就会去跑另一段程序,时间不固定),调用一次驱动去读取数据的过程中(时间较长相对于时间片),这期间CPU去做其他事情了,等重新回来读取数据时,有可能错过了时序中的某个片段,从而出现有时读取数据正常,有时错误这种现象。
相关文章推荐
- 《Linux内核分析》第二周学习笔记
- Linux 安装jdk和配置
- Linux多线程编程的时候如何查看一个进程中的某个线程是否存活
- 《Linux操作系统分析》之分析精简的Linux的内核中断和时间片轮询
- Linux chown 命令
- Linux下编译安装MySQL5.6
- Linux下如何使用图形界面工具调试程序
- find:paths must precede expression问题及解决
- Linux多线程及同步
- linux scp远程拷贝文件及文件夹
- Linux系统中MySQL数据库操作命令(未整理)
- Linux 后台进程与守护进程
- Linux统计某文件夹下文件、文件夹的个数
- Linux常用目录的作用
- linux运维实战练习-2016年3月4日-3月19日课程作业(练习)安排
- Linux内核文件系统学习:虚拟文件系统(多图)
- 安装Linux后需要了解的
- linux逻辑卷管理
- linux下命令行安装hadoop2.7.2过程
- linux 安装 youcompleteme