1. 程式人生 > >將DHT11移植到Linux系統上(轉)

將DHT11移植到Linux系統上(轉)

ati amp 裸奔 電平 repl bre details 現象 word

由於項目需要,需要將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. #define DEVICE_NAME "dht11"
  20. #define PIN S5PV210_GPH0(0)
  21. typedef unsigned char U8;
  22. unsigned char buf[6];
  23. unsigned char check_flag;
  24. //spinlock_t lock=SPIN_LOCK_UNLOCKED;
  25. //spinlock_t lock=SPIN_LOCK_UNLOCKED;
  26. //DEFINE_SPINLOCK(lock);
  27. static DEFINE_MUTEX(mutex);
  28. int read_one_bit(void) //從io口中讀一個字節
  29. {
  30. gpio_direction_input(PIN);
  31. return gpio_get_value(PIN);
  32. }
  33. void gpio_out(int value) //將io口設置為輸出,並設置電平
  34. {
  35. gpio_direction_output(PIN,value);
  36. }
  37. unsigned char humidity_read_byte(void)
  38. {
  39. int i=0;
  40. int num;
  41. unsigned char flag=0;
  42. unsigned char data=0;
  43. for(num=0;num<8;num++)
  44. {
  45. i=0;
  46. while(!gpio_get_value(PIN))
  47. {
  48. udelay(10);
  49. i++;
  50. if(i>10)
  51. break;
  52. }
  53. flag=0x0;
  54. udelay(28);
  55. if(gpio_get_value(PIN))
  56. {
  57. flag=0x01;
  58. }
  59. i=0;
  60. while(gpio_get_value(PIN))
  61. {
  62. udelay(10);
  63. i++;
  64. if(i>12)
  65. break;
  66. }
  67. data<<=1;
  68. data|=flag;
  69. }
  70. return data;
  71. }
  72. void humidity_read_data(void)
  73. {
  74. int i=0;
  75. gpio_out(0);
  76. mdelay(30);
  77. gpio_out(1);
  78. udelay(20);
  79. if(read_one_bit()== 0)
  80. {
  81. while(!gpio_get_value(PIN))
  82. {
  83. udelay(5);
  84. i++;
  85. if(i>20)
  86. {
  87. printk("humidity_read_data %d err!\n",__LINE__);
  88. break;
  89. }
  90. }
  91. i=0;
  92. while(gpio_get_value(PIN))
  93. {
  94. udelay(5);
  95. i++;
  96. if(i>20)
  97. {
  98. printk("humidity_read_data %d err!\n",__LINE__);
  99. break;
  100. }
  101. }
  102. for(i=0;i<5;i++)
  103. buf[i]=humidity_read_byte();
  104. buf[5]=buf[0]+buf[1]+buf[2]+buf[3];
  105. if(buf[4]==buf[5])
  106. {
  107. check_flag=0xff;
  108. printk("humidity check pass\n");
  109. printk("humidity=[%d],temp=[%d]\n",buf[0],buf[2]);
  110. }
  111. else
  112. {
  113. check_flag=0x0;
  114. printk("humidity check fail\n");
  115. }
  116. }
  117. }
  118. static ssize_t humidiy_read(struct file *file, char __user *buffer, size_t size, loff_t *off)
  119. {
  120. int ret;
  121. local_irq_disable();
  122. humidity_read_data();
  123. local_irq_enable();
  124. if(check_flag==0xff)
  125. {
  126. ret=copy_to_user(buffer,buf,sizeof(buf));
  127. if(ret<0){
  128. printk("copy to user err\n");
  129. return -EAGAIN;
  130. }
  131. else
  132. return 0;
  133. }
  134. else
  135. return -EAGAIN;
  136. }
  137. static int humidiy_open(struct inode *inode, struct file *file)
  138. {
  139. printk("open in kernel\n");
  140. return 0;
  141. }
  142. static int humidiy_release(struct inode *inode, struct file *file)
  143. {
  144. printk("humidity release\n");
  145. return 0;
  146. }
  147. static struct file_operations humidity_dev_fops={
  148. .owner = THIS_MODULE,
  149. .open = humidiy_open,
  150. .read = humidiy_read,
  151. .release = humidiy_release,
  152. };
  153. static struct miscdevice humidity_dev = {
  154. .minor = MISC_DYNAMIC_MINOR,
  155. .name = DEVICE_NAME,
  156. .fops = &humidity_dev_fops,
  157. };
  158. static int __init humidity_dev_init(void)
  159. {
  160. int ret;
  161. ret = gpio_request(PIN , "humidity");
  162. if (ret){
  163. printk("%s: request GPIO %d for humidity failed, ret = %d\n", DEVICE_NAME,PIN , ret);
  164. return ret;
  165. }
  166. gpio_direction_output(PIN, 1);
  167. ret = misc_register(&humidity_dev);
  168. printk("humidity_dev_init\n");
  169. return ret;
  170. }
  171. static void __exit humidity_dev_exit(void)
  172. {
  173. gpio_free(PIN);
  174. misc_deregister(&humidity_dev);
  175. }
  176. module_init(humidity_dev_init);
  177. module_exit(humidity_dev_exit);
  178. MODULE_LICENSE("GPL");
  179. 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\n");
  15. return 0; }
  16. while(1){
  17. ret=read(humidityfd,buf,sizeof(buf));
  18. if(ret<0)
  19. printf("read err!\n");
  20. else{
  21. humidiyz =buf[0];
  22. humidiyx =buf[1];
  23. tempz =buf[2] ;
  24. tempx =buf[3];
  25. printf("humidity = %d.%d%%\n", humidiyz, humidiyx);
  26. printf("temp = %d.%d\n",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

將DHT11移植到Linux系統上(轉)