歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> mini2440上DS18B20的驅動程序(含簡單測試)

mini2440上DS18B20的驅動程序(含簡單測試)

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

ds18b20_drv.c

[cpp]

  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. /* 相關引腳定義,方便以後移植 */
  17. #define DQ S3C2410_GPF(3)
  18. #define CFG_IN S3C2410_GPIO_INPUT
  19. #define CFG_OUT S3C2410_GPIO_OUTPUT
  20. // ds18b20主次設備號(動態分配)
  21. static int ds18b20_major = 0;
  22. static int ds18b20_minor = 0;
  23. static int ds18b20_nr_devs = 1;
  24. // 定義設備類型
  25. static struct ds18b20_device
  26. {
  27. struct cdev cdev;
  28. };
  29. struct ds18b20_device *ds18b20_devp; /*設備結構體指針 */
  30. static struct class *ds18b20_class;
  31. static struct class_device *ds18b20_class_dev;
  32. /* 函數聲明 */
  33. static int ds18b20_open(struct inode *inode, struct file *filp);
  34. static int ds18b20_init(void);
  35. static void write_byte(unsigned char data);
  36. static unsigned char read_byte(void);
  37. static ssize_t ds18b20_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos);
  38. void ds18b20_setup_cdev(struct ds18b20_device *dev, int index);
  39. static int ds18b20_open(struct inode *inode, struct file *filp)
  40. {
  41. int flag = 0;
  42. flag = ds18b20_init();
  43. if (flag & 0x01)
  44. {
  45. printk(KERN_WARNING "open ds18b20 failed\n");
  46. return -1;
  47. }
  48. printk(KERN_NOTICE "open ds18b20 successful\n");
  49. return 0;
  50. }
  51. static int ds18b20_init(void)
  52. {
  53. int retval = 0;
  54. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  55. s3c2410_gpio_pullup(DQ, 0);
  56. s3c2410_gpio_setpin(DQ, 1);
  57. udelay(2);
  58. s3c2410_gpio_setpin(DQ, 0); // 拉低ds18b20總線,復位ds18b20
  59. udelay(500); // 保持復位電平500us
  60. s3c2410_gpio_setpin(DQ, 1); // 釋放ds18b20總線
  61. udelay(60);
  62. // 若復位成功,ds18b20發出存在脈沖(低電平,持續60~240us)
  63. s3c2410_gpio_cfgpin(DQ, CFG_IN);
  64. retval = s3c2410_gpio_getpin(DQ);
  65. udelay(500);
  66. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  67. s3c2410_gpio_pullup(DQ, 0);
  68. s3c2410_gpio_setpin(DQ, 1); // 釋放總線
  69. return retval;
  70. }
  71. static void write_byte(unsigned char data)
  72. {
  73. int i = 0;
  74. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  75. s3c2410_gpio_pullup(DQ, 1);
  76. for (i = 0; i < 8; i++)
  77. {
  78. // 總線從高拉至低電平時,就產生寫時隙
  79. s3c2410_gpio_setpin(DQ, 1);
  80. udelay(2);
  81. s3c2410_gpio_setpin(DQ, 0);
  82. s3c2410_gpio_setpin(DQ, data & 0x01);
  83. udelay(60);
  84. data >>= 1;
  85. }
  86. s3c2410_gpio_setpin(DQ, 1); // 重新釋放ds18b20總線
  87. }
  88. static unsigned char read_byte(void)
  89. {
  90. int i;
  91. unsigned char data = 0;
  92. for (i = 0; i < 8; i++)
  93. {
  94. // 總線從高拉至低,只需維持低電平17ts,再把總線拉高,就產生讀時隙
  95. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  96. s3c2410_gpio_pullup(DQ, 0);
  97. s3c2410_gpio_setpin(DQ, 1);
  98. udelay(2);
  99. s3c2410_gpio_setpin(DQ, 0);
  100. udelay(2);
  101. s3c2410_gpio_setpin(DQ, 1);
  102. udelay(8);
  103. data >>= 1;
  104. s3c2410_gpio_cfgpin(DQ, CFG_IN);
  105. if (s3c2410_gpio_getpin(DQ))
  106. data |= 0x80;
  107. udelay(50);
  108. }
  109. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  110. s3c2410_gpio_pullup(DQ, 0);
  111. s3c2410_gpio_setpin(DQ, 1); // 釋放ds18b20總線
  112. return data;
  113. }
  114. static ssize_t ds18b20_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos)
  115. {
  116. int flag;
  117. unsigned long err;
  118. unsigned char result[2] = { 0x00, 0x00 };
  119. //struct ds18b20_device *dev = filp->private_data;
  120. flag = ds18b20_init();
  121. if (flag & 0x01)
  122. {
  123. printk(KERN_WARNING "ds18b20 init failed\n");
  124. return -1;
  125. }
  126. write_byte(0xcc);
  127. write_byte(0x44);
  128. flag = ds18b20_init();
  129. if (flag & 0x01)
  130. return -1;
  131. write_byte(0xcc);
  132. write_byte(0xbe);
  133. result[0] = read_byte(); // 溫度低八位
  134. result[1] = read_byte(); // 溫度高八位
  135. err = copy_to_user(buf, &result, sizeof(result));
  136. return err ? -EFAULT : min(sizeof(result), count);
  137. }
  138. static struct file_operations ds18b20_dev_fops = {
  139. .owner = THIS_MODULE,
  140. .open = ds18b20_open,
  141. .read = ds18b20_read,
  142. };
  143. void ds18b20_setup_cdev(struct ds18b20_device *dev, int index)
  144. {
  145. int err, devno = MKDEV(ds18b20_major, ds18b20_minor + index);
  146. cdev_init(&dev->cdev, &ds18b20_dev_fops);
  147. dev->cdev.owner = THIS_MODULE;
  148. err = cdev_add(&(dev->cdev), devno, 1);
  149. if (err)
  150. {
  151. printk(KERN_NOTICE "ERROR %d add ds18b20\n", err);
  152. }
  153. }
  154. static int __init ds18b20_dev_init(void)
  155. {
  156. int result;
  157. dev_t dev = 0;
  158. dev = MKDEV(ds18b20_major, ds18b20_minor);
  159. if (ds18b20_major)
  160. {
  161. result = register_chrdev_region(dev, ds18b20_nr_devs, "ds18b20");
  162. }
  163. else
  164. {
  165. result = alloc_chrdev_region(&dev, ds18b20_minor, ds18b20_nr_devs, "ds18b20");
  166. ds18b20_major = MAJOR(dev);
  167. }
  168. if (result < 0)
  169. {
  170. printk(KERN_WARNING "ds18b20: failed to get major\n");
  171. return result;
  172. }
  173. /* 為新設備分配內存和初始化 */
  174. ds18b20_devp = kmalloc(sizeof(struct ds18b20_device), GFP_KERNEL);
  175. if (!ds18b20_devp)
  176. { /*申請失敗 */
  177. result = -ENOMEM;
  178. goto fail_malloc;
  179. }
  180. memset(ds18b20_devp, 0, sizeof(struct ds18b20_device));
  181. ds18b20_setup_cdev(ds18b20_devp, 0);
  182. /* 自動創建設備節點 */
  183. ds18b20_class = class_create(THIS_MODULE, "ds18b20_sys_class");
  184. if (IS_ERR(ds18b20_class))
  185. return PTR_ERR(ds18b20_class);
  186. ds18b20_class_dev =
  187. device_create(ds18b20_class, NULL, MKDEV(ds18b20_major, 0), NULL, "ds18b20");
  188. if (unlikely(IS_ERR(ds18b20_class_dev)))
  189. return PTR_ERR(ds18b20_class_dev);
  190. return 0;
  191. fail_malloc:
  192. unregister_chrdev_region(dev, 1);
  193. return result;
  194. }
  195. static void __exit ds18b20_dev_exit(void)
  196. {
  197. cdev_del(&ds18b20_devp->cdev); /*注銷cdev */
  198. kfree(ds18b20_devp); /*釋放設備結構體內存 */
  199. unregister_chrdev_region(MKDEV(ds18b20_major, 0), ds18b20_nr_devs); /*釋放設備號 */
  200. device_unregister(ds18b20_class_dev);
  201. class_destroy(ds18b20_class);
  202. }
  203. module_init(ds18b20_dev_init);
  204. module_exit(ds18b20_dev_exit);
  205. MODULE_LICENSE("Dual BSD/GPL");
  206. MODULE_AUTHOR("[email protected]");
app-ds18b20.c

[cpp]

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <linux/ioctl.h>
  5. // 函數聲明
  6. void ds18b20_delay(int i);
  7. int main()
  8. {
  9. int fd, i;
  10. unsigned char result[2]; // 從ds18b20讀出的結果,result[0]存放低八位
  11. unsigned char integer_value = 0;
  12. float decimal_value = 0; // 溫度數值,decimal_value為小數部分的值
  13. float temperature = 0;
  14. fd = open("/dev/ds18b20", 0);
  15. if (fd < 0)
  16. {
  17. perror("open device failed\n");
  18. exit(1);
  19. }
  20. while (1)
  21. {
  22. i++;
  23. read(fd, &result, sizeof(result));
  24. integer_value = ((result[0] & 0xf0) >> 4) | ((result[1] & 0x07) << 4);
  25. // 精確到0.25度
  26. decimal_value = 0.5 * ((result[0] & 0x0f) >> 3) + 0.25 * ((result[0] & 0x07) >> 2);
  27. temperature = (float)integer_value + decimal_value;
  28. printf("Current Temperature:%6.2f\n", temperature);
  29. ds18b20_delay(500);
  30. }
  31. }
  32. void ds18b20_delay(int i)
  33. {
  34. int j, k;
  35. for (j = 0; j < i; j++)
  36. for (k = 0; k < 50000; k++) ;
  37. }
Makefile

[cpp]

  1. ifneq ($(KERNELRELEASE),)
  2. obj-m := ds18b20_drv.o
  3. else
  4. KDIR := /home/youshan/linux-2.6.32.2
  5. MYAPP := app-ds18b20
  6. all:
  7. make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
  8. arm-linux-gcc $(MYAPP).c -o $(MYAPP)
  9. clean:
  10. rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul*
  11. rm -f $(MYAPP)
  12. endif

運行結果:

[cpp]

  1. [[email protected] home]#
  2. [[email protected] home]#./app-ds18b20
  3. open ds18b20 successful
  4. Current Temperature: 23.50
  5. Current Temperature: 23.50
  6. Current Temperature: 23.25
  7. Current Temperature: 23.50
  8. Current Temperature: 23.50
  9. Current Temperature: 23.50
  10. ^C
  11. [[email protected] home]#
Copyright © Linux教程網 All Rights Reserved