将DHT11移植到Linux系统上(转)

由于项目需要,需要将DHT11移植到Linux。驱动程序如下

[plain] view plain copy
 
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/slab.h>  
  4. #include <linux/input.h>  
  5. #include <linux/init.h>  
  6. #include <linux/errno.h>  
  7. #include <linux/serio.h>  
  8. #include <linux/delay.h>  
  9. #include <linux/clk.h>  
  10. #include <linux/wait.h>  
  11. #include <linux/sched.h>  
  12. #include <linux/cdev.h>  
  13. #include <linux/miscdevice.h>  
  14. #include <linux/gpio.h>  
  15. #include <mach/gpio.h>  
  16. #include <asm-generic/uaccess.h>  
  17. #include <linux/spinlock.h>  
  18. #include <linux/mutex.h>  
  19.   
  20.   
  21. #define DEVICE_NAME "dht11"  
  22. #define PIN S5PV210_GPH0(0)  
  23.   
  24. typedef unsigned char  U8;   
  25. unsigned char buf[6];  
  26. unsigned char check_flag;  
  27. //spinlock_t lock=SPIN_LOCK_UNLOCKED;  
  28.   
  29. //spinlock_t lock=SPIN_LOCK_UNLOCKED;  
  30.   
  31. //DEFINE_SPINLOCK(lock);  
  32. static  DEFINE_MUTEX(mutex);  
  33. int read_one_bit(void)          //从io口中读一个字节  
  34. {  
  35.     gpio_direction_input(PIN);  
  36.     return gpio_get_value(PIN);  
  37. }  
  38.   
  39.   
  40. void gpio_out(int value)   //将io口设置为输出,并设置电平  
  41. {  
  42.     gpio_direction_output(PIN,value);  
  43. }  
  44.   
  45. unsigned char  humidity_read_byte(void)  
  46. {      
  47.     int i=0;  
  48.     int num;   
  49.     unsigned char flag=0;  
  50.     unsigned char data=0;  
  51.       
  52.   
  53.     for(num=0;num<8;num++)  
  54.     {                
  55.           i=0;  
  56.           while(!gpio_get_value(PIN))  
  57.           {  
  58.             udelay(10);  
  59.             i++;  
  60.             if(i>10)  
  61.             break;  
  62.            }  
  63.             flag=0x0;  
  64.             udelay(28);              
  65.            if(gpio_get_value(PIN))  
  66.            {  
  67.             flag=0x01;            
  68.            }  
  69.             i=0;  
  70.            while(gpio_get_value(PIN))  
  71.            {  
  72.             udelay(10);  
  73.             i++;  
  74.             if(i>12)  
  75.             break;  
  76.            }  
  77.            data<<=1;  
  78.            data|=flag;  
  79.     }    
  80.     return data;  
  81. }  
  82.   
  83.   
  84. void humidity_read_data(void)  
  85. {  
  86.     int i=0;  
  87.     gpio_out(0);  
  88.     mdelay(30);  
  89.     gpio_out(1);  
  90.     udelay(20);      
  91.     if(read_one_bit()== 0)  
  92.     {   
  93.         while(!gpio_get_value(PIN))  
  94.         {  
  95.            udelay(5);  
  96.            i++;  
  97.             if(i>20)  
  98.             {  
  99.                 printk("humidity_read_data %d err! ",__LINE__);  
  100.                 break;  
  101.             }  
  102.         }  
  103.         i=0;  
  104.         while(gpio_get_value(PIN))  
  105.         {  
  106.            udelay(5);  
  107.            i++;  
  108.            if(i>20)  
  109.            {  
  110.               printk("humidity_read_data %d err! ",__LINE__);  
  111.               break;  
  112.            }  
  113.         }  
  114.         for(i=0;i<5;i++)  
  115.         buf[i]=humidity_read_byte();    
  116.          
  117.         buf[5]=buf[0]+buf[1]+buf[2]+buf[3];  
  118.   
  119.         if(buf[4]==buf[5])  
  120.         {  
  121.            check_flag=0xff;  
  122.            printk("humidity check pass ");  
  123.            printk("humidity=[%d],temp=[%d] ",buf[0],buf[2]);  
  124.         }  
  125.         else  
  126.         {  
  127.            check_flag=0x0;  
  128.            printk("humidity check fail ");             
  129.         }                     
  130.     }  
  131. }  
  132.   
  133.   
  134. static ssize_t humidiy_read(struct file *file, char __user *buffer, size_t size, loff_t *off)  
  135. {  
  136.         int ret;  
  137.         local_irq_disable();  
  138.         humidity_read_data();  
  139.         local_irq_enable();  
  140.         if(check_flag==0xff)  
  141.         {  
  142.              ret=copy_to_user(buffer,buf,sizeof(buf));  
  143.              if(ret<0){  
  144.               printk("copy to user err ");  
  145.               return -EAGAIN;  
  146.               }  
  147.              else  
  148.              return  0;  
  149.          }  
  150.          else  
  151.              return -EAGAIN;      
  152. }  
  153.   
  154. static int humidiy_open(struct inode *inode, struct file *file)  
  155. {  
  156.     printk("open in kernel ");  
  157.     return 0;  
  158. }  
  159.   
  160. static int humidiy_release(struct inode *inode, struct file *file)  
  161. {  
  162.     printk("humidity release ");  
  163.     return 0;  
  164. }  
  165.   
  166. static struct file_operations humidity_dev_fops={  
  167.     .owner          = THIS_MODULE,  
  168.     .open           = humidiy_open,  
  169.     .read           = humidiy_read,  
  170.     .release        = humidiy_release,  
  171. };  
  172.   
  173. static struct miscdevice humidity_dev = {  
  174.     .minor          = MISC_DYNAMIC_MINOR,  
  175.     .name           = DEVICE_NAME,  
  176.     .fops           = &humidity_dev_fops,  
  177. };  
  178.   
  179. static int __init humidity_dev_init(void)   
  180. {  
  181.     int ret;  
  182.     ret = gpio_request(PIN , "humidity");  
  183.     if (ret){  
  184.       printk("%s: request GPIO %d for humidity failed, ret = %d ", DEVICE_NAME,PIN , ret);  
  185.       return ret;  
  186.     }  
  187.     gpio_direction_output(PIN, 1);  
  188.     ret = misc_register(&humidity_dev);  
  189.     printk("humidity_dev_init ");  
  190.     return ret;  
  191. }  
  192.   
  193. static void __exit humidity_dev_exit(void)  
  194. {  
  195.     gpio_free(PIN);  
  196.     misc_deregister(&humidity_dev);  
  197. }  
  198.   
  199. module_init(humidity_dev_init);  
  200. module_exit(humidity_dev_exit);  
  201.   
  202. MODULE_LICENSE("GPL");  
  203. MODULE_AUTHOR("WWW")  


测试程序如下

[plain] view plain copy
 
  1. #include<stdio.h>  
  2. #include<sys/types.h>  
  3. int main()  
  4. {  
  5.     int humidityfd;  
  6.     int ret;  
  7.     char buf[5];  
  8.     unsigned char  tempz = 0;  
  9.     unsigned char  tempx = 0;       
  10.     unsigned char  humidiyz = 0;  
  11.     unsigned char  humidiyx = 0;      
  12.     humidityfd = open("/dev/humidity",0);  
  13.     if(humidityfd<0){  
  14.         printf("/dev/humidiy open fail ");  
  15.         return 0;       }                             
  16.     while(1){         
  17.     ret=read(humidityfd,buf,sizeof(buf));  
  18.                 if(ret<0)  
  19.                 printf("read err! ");  
  20.                 else{  
  21.         humidiyz  =buf[0];    
  22.         humidiyx  =buf[1];    
  23.         tempz     =buf[2] ;       
  24.         tempx     =buf[3];        
  25.         printf("humidity = %d.%d%% ", humidiyz, humidiyx);  
  26.         printf("temp = %d.%d ",tempz,tempx);     
  27.                 }  
  28.         sleep(2);  
  29.     }  
  30.     close(humidityfd);  
  31.     return 0;  
  32. }  

本想,这驱动调试起来应该简单的。但在调试到过程中,发现采集到的数据有时正确,有时错误,成功率约为50%。于是按照手册微调一下时序,并没有解决问题。网上查阅相关资料,发现都是用单片机来编程的。当程序本来就是以裸奔的思想跑的,为什么移植到Linux会出错呢?从dht11出来的信号都正常啊。误打误撞,使用local_irq_disable这个函数后,读出的数据都正常啦。local_irq_disable通过屏蔽中断标志位,从而禁止内核的抢占。我猜测是Linux是个多任务系统,该系统按照一定的算法(每隔一段时间就会去跑另一段程序,时间不固定),调用一次驱动去读取数据的过程中(时间较长相对于时间片),这期间CPU去做其他事情了,等重新回来读取数据时,有可能错过了时序中的某个片段,从而出现有时读取数据正常,有时错误这种现象。

http://blog.csdn.net/mike8825/article/details/50804978

原文地址:https://www.cnblogs.com/xihong2014/p/7208424.html