歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> mini2440 驅動ds18b20

mini2440 驅動ds18b20

日期:2017/3/1 10:49:49   编辑:Linux編程

想著有個ds18b20,於是就寫了一個18b20的驅動。是在mini2440上面實現的。

ldd3的大師說得好,linux驅動應該盡可能多的提供機制,而不是提供策略。我覺得說得太有道理了。驅動本身就不應該涉及到太多策略問題,策略問題應該盡可能多的由應用程序去提供。作為驅動,應該盡可能多得去實現提供硬件的功能,然後留出接口給上面的應用程序調用。

其實ds18b20驅動比較簡單,無非就是在單片機驅動18b20的基礎上,家裡一個字符驅動設備的外套。下面直接上代碼吧。

驅動代碼:

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/delay.h>
  4. #include <linux/kernel.h>
  5. #include <linux/moduleparam.h>
  6. #include <linux/init.h>
  7. #include <linux/types.h>
  8. #include <linux/fs.h>
  9. #include <mach/regs-gpio.h>
  10. #include <mach/hardware.h>
  11. #include <linux/cdev.h>
  12. #include <asm/uaccess.h>
  13. #include <linux/errno.h>
  14. #include <linux/gpio.h>
  15. #include <linux/device.h> //自動創建設備需要此頭文件
  16. #define DQ S3C2410_GPF(3) //mini2440裡面是這樣定義GPIO的
  17. #define DQ_IN S3C2410_GPIO_INPUT //設置DQ為輸入
  18. #define DQ_OUT S3C2410_GPIO_OUTPUT //設置DQ為輸入
  19. #define D_MAJOR 0 //定義主設備號
  20. #define D_MINOR 0 //定義從設備號
  21. #define DEV_NAME "ds18b20" //定義設備名
  22. static int ds18b20_major = D_MAJOR;//ds18b20主設備號
  23. static int ds18b20_minor = D_MINOR;//ds18b20從設備號
  24. static struct class *my_class; //定義class,用於自動掛載設備
  25. static struct class_device *my_device; //自動掛載設備
  26. static struct ds18b20_dev{ //放在一個結構體中
  27. struct cdev cdev; //這個結構體比較簡單,但是建議以後將用戶的東西都放在一個結構體中
  28. };
  29. struct ds18b20_dev *ds18b20_devp;
  30. void ds18b20_reset(void) //重啟ds18b20
  31. {
  32. s3c2410_gpio_cfgpin(DQ, DQ_OUT); //設置為輸出
  33. s3c2410_gpio_pullup(DQ, 0); //設置下拉
  34. s3c2410_gpio_setpin(DQ, 0); //拉低總線
  35. udelay(500); //需要將總線拉低480~950us
  36. s3c2410_gpio_setpin(DQ, 1); //釋放總線
  37. udelay(60); //DS18B20拉低信號,60~240us表示應答
  38. s3c2410_gpio_cfgpin(DQ, DQ_IN); //讀入DS18B20拉低信號
  39. while(s3c2410_gpio_getpin(DQ)); //等待DS18B20應答
  40. while(!s3c2410_gpio_getpin(DQ)); //等待DS18B20釋放總線
  41. }
  42. void write_ds18b20(unsigned char Data) //寫命令到ds18b20
  43. {
  44. unsigned char i;
  45. s3c2410_gpio_cfgpin(DQ, DQ_OUT); //設置為輸出
  46. s3c2410_gpio_pullup(DQ, 1); //���拉
  47. for(i=0;i<8;i++){
  48. s3c2410_gpio_setpin(DQ, 0); //拉低總線
  49. udelay(10); //需要拉低10~15us
  50. if(Data&0x01)
  51. s3c2410_gpio_setpin(DQ, 1);
  52. else
  53. s3c2410_gpio_setpin(DQ, 0);
  54. udelay(40); //需要拉低20~40us來寫0
  55. s3c2410_gpio_setpin(DQ, 1); //釋放總線
  56. udelay(1); //稍微延時
  57. Data >>= 1;
  58. }
  59. }
  60. static unsigned char read_ds18b20(void) //讀ds18b20
  61. {
  62. unsigned char Temp=0,i;
  63. for(i=0;i<8;i++){
  64. Temp >>= 1;
  65. s3c2410_gpio_cfgpin(DQ, DQ_OUT); //DQ為輸出狀態
  66. s3c2410_gpio_setpin(DQ, 0); //拉低總線,啟動輸入
  67. udelay(1); //拉低總線約1us
  68. s3c2410_gpio_setpin(DQ, 1); //釋放總線
  69. s3c2410_gpio_cfgpin(DQ, DQ_IN); //DQ為輸入狀態
  70. if(s3c2410_gpio_getpin(DQ))
  71. Temp |= 0x80;
  72. udelay(45); //延時45us
  73. }
  74. return Temp;
  75. }
  76. static int ds18b20_open(struct inode *inode,struct file *filp)
  77. {
  78. filp->private_data = ds18b20_devp;
  79. ds18b20_reset();
  80. printk(KERN_NOTICE "open ds18b20 successful\n");
  81. return 0;
  82. }
  83. static ssize_t ds18b20_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos)
  84. {
  85. unsigned long err;
  86. struct ds18b20_dev *dev = filp->private_data;
  87. unsigned char result[2] = {0x00, 0x00}; //這個是用來存放從ds18b20讀到的值
  88. ds18b20_reset(); //reset ds18b20
  89. write_ds18b20(0xCC); //跳過ROM
  90. write_ds18b20(0x44); //溫度轉換
  91. ds18b20_reset(); //reset ds18b20
  92. write_ds18b20(0xCC); //跳過ROM
  93. write_ds18b20(0xbe); //讀取RAM
  94. result[0] = read_ds18b20(); //讀低8位,存放在result[0]
  95. result[1] = read_ds18b20(); //讀高8位,存放在result[1]
  96. ds18b20_reset();
  97. err = copy_to_user(buf, &result, sizeof(result));
  98. return err ? -EFAULT : min(sizeof(result), size);
  99. }
  100. static int ds18b20_release(struct inode *inode,struct file *filp)
  101. {
  102. return 0;
  103. }
  104. static const struct file_operations ds18b20_fops={
  105. .owner=THIS_MODULE,
  106. .read=ds18b20_read,
  107. .open=ds18b20_open,
  108. .release=ds18b20_release,
  109. };
  110. void ds18b20_setup_dev(struct ds18b20_dev *dev,int minor)
  111. {
  112. int err;
  113. int devno;
  114. devno = MKDEV(ds18b20_major,minor);
  115. cdev_init(&dev->cdev,&ds18b20_fops);
  116. dev->cdev.owner=THIS_MODULE;
  117. dev->cdev.ops=&ds18b20_fops;
  118. err=cdev_add(&dev->cdev,devno,1);
  119. if(err)
  120. printk(KERN_NOTICE "Error %d adding %d\n",err,minor);
  121. }
  122. static int __init ds18b20_init(void)
  123. {
  124. int result;
  125. dev_t devno = 0;
  126. if(ds18b20_major){
  127. devno = MKDEV(ds18b20_major,ds18b20_minor);
  128. result = register_chrdev_region(devno,1,DEV_NAME);
  129. }
  130. else{
  131. result = alloc_chrdev_region(&devno,0,1,DEV_NAME);
  132. ds18b20_major = MAJOR(devno);
  133. }
  134. if(result < 0)
  135. return result;
  136. ds18b20_devp = kmalloc(sizeof(struct ds18b20_dev),GFP_KERNEL);
  137. if(ds18b20_devp){
  138. result = -ENOMEM;
  139. goto fail_malloc;
  140. }
  141. memset(ds18b20_devp,0,sizeof(struct ds18b20_dev));
  142. ds18b20_setup_dev(ds18b20_devp,0);
  143. my_class = class_create(THIS_MODULE,"ds18b20_class");
  144. /*在linux 2.6.27之前是:class_device_create*/
  145. my_device = device_create(my_class,NULL,MKDEV(ds18b20_major, ds18b20_minor),NULL,"ds18b20");
  146. return 0;
  147. fail_malloc:
  148. unregister_chrdev_region(devno,1);
  149. return result;
  150. }
  151. static void __exit ds18b20_exit(void)
  152. {
  153. cdev_del(&ds18b20_devp->cdev);
  154. kfree(ds18b20_devp);
  155. device_destroy(my_class, MKDEV(ds18b20_major, ds18b20_minor));//刪除設備文件 /dev/ds18b20
  156. class_destroy(my_class); //刪除創建的bus
  157. unregister_chrdev_region(MKDEV(ds18b20_major,ds18b20_minor),1);
  158. }
  159. module_init(ds18b20_init);
  160. module_exit(ds18b20_exit);
  161. MODULE_LICENSE("GPL");
  162. MODULE_AUTHOR("WIOT");
Copyright © Linux教程網 All Rights Reserved