嵌入式开发平台:mini2440

DS18B20 所用GPIO:S3C2410_GPF(3)

一、DS18B20 时序分析

DS18B20的一线工作协议流程是:初始化→ROM操作指令→存储器操作指令→数据传输,其工作时序包括:初始化时序、写时序、读时序。

1、初始化时序

主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答,若无低电平出现一直都是高电平说明总线上无器件应答。

   作为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备,若没有检测到就一直在检测等待。

[cpp] view plaincopy
  1. static int ds18b20_init(void)
  2. {
  3. int retval = 0;
  4. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  5. s3c2410_gpio_pullup(DQ, 0);
  6. s3c2410_gpio_setpin(DQ, 1);
  7. udelay(2);
  8. s3c2410_gpio_setpin(DQ, 0); // 拉低ds18b20总线,复位ds18b20
  9. udelay(500);                // 保持复位电平500us
  10. s3c2410_gpio_setpin(DQ, 1); // 释放ds18b20总线
  11. udelay(60);
  12. // 若复位成功,ds18b20发出存在脉冲(低电平,持续60~240us)
  13. s3c2410_gpio_cfgpin(DQ, CFG_IN);
  14. retval = s3c2410_gpio_getpin(DQ);
  15. udelay(500);
  16. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  17. s3c2410_gpio_pullup(DQ, 0);
  18. s3c2410_gpio_setpin(DQ, 1); // 释放总线
  19. return retval;
  20. }

2、写时序

写周期最少为60微秒,最长不超过120微秒,写周期一开始作为主机先把总线拉低1微秒表示写周期开始,随后若主机想写0,则继续拉低电平最少60微秒直至写周期结束,然后释放总线为高电平;若主机想写1,在一开始拉低总线电平1微秒后就释放总线为高电平,一直到写周期结束。

而作为从机的DS18B20则在检测到总线被拉低后等待15微秒然后从15μs到45μs开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。

[cpp] view plaincopy
  1. static void write_byte(unsigned char data)
  2. {
  3. int i = 0;
  4. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  5. s3c2410_gpio_pullup(DQ, 1);
  6. for (i = 0; i < 8; i++)
  7. {
  8. // 总线从高拉至低电平时,就产生写时隙
  9. s3c2410_gpio_setpin(DQ, 1);
  10. udelay(2);
  11. s3c2410_gpio_setpin(DQ, 0);
  12. s3c2410_gpio_setpin(DQ, data & 0x01);
  13. udelay(60);
  14. data >>= 1;
  15. }
  16. s3c2410_gpio_setpin(DQ, 1); // 重新释放ds18b20总线
  17. }

3、读时序

对于读数据操作时序也分为读0时序和读1时序两个过程,读时序是从主机把单总线拉低之后,在1微秒之后就得释放单总线为高电平,以让DS18B20把数据传输到单总线上。DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束;若要送出1则释放总线为高电平。

主机在一开始拉低总线1微秒后释放总线,然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为0,采样期内总线为高电平则确认为1,完成一个读时序过程,至少需要60μs才能完成。

[cpp] view plaincopy
  1. static unsigned char read_byte(void)
  2. {
  3. int i;
  4. unsigned char data = 0;
  5. // 总线从高拉至低,只需维持低电平17ts,再把总线拉高,就产生读时隙
  6. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  7. s3c2410_gpio_pullup(DQ, 0);
  8. for (i = 0; i < 8; i++)
  9. {
  10. s3c2410_gpio_setpin(DQ, 1);
  11. udelay(2);
  12. s3c2410_gpio_setpin(DQ, 0);
  13. udelay(2);
  14. s3c2410_gpio_setpin(DQ, 1);
  15. udelay(8);
  16. data >>= 1;
  17. s3c2410_gpio_cfgpin(DQ, CFG_IN);
  18. if (s3c2410_gpio_getpin(DQ))
  19. data |= 0x80;
  20. udelay(50);
  21. }
  22. s3c2410_gpio_cfgpin(DQ, CFG_OUT);
  23. s3c2410_gpio_pullup(DQ, 0);
  24. s3c2410_gpio_setpin(DQ, 1); // 释放ds18b20总线
  25. return data;
  26. }

二、操作方法

DS18B20单线通信功能是分时完成的,有严格的时序概念,如果出现序列混乱,1-WIRE器件将不影响主机,因此读写时序很重要。系统对DS18B20的各种操作必须按协议进行,根据DS18B20的协议规定,微控制器控制DS18B20完成温度的转换必须经过以下4个步骤:

1)每次读写前对DS18B20进行复位初始化。复位要求主CPU将数据线下拉500μs,然后释放,DS18B20收到信号后等待16μs-60μs左右,然后发出60μs-240μs的存在低脉冲,主CPU收到此信号后表示复位成功。


2)发送一条ROM指令

3)发送存储器指令


1、让DS18B20进行一次温度转换的具体操作如下:

a -- 主机先做个复位操作;
b -- 主机再写跳过ROM的操作(CCH)命令;
c -- 然后主机接着写转换温度的操作指令,后面释放总线至少1秒,让DS18B20完成转换操作。需要注意的是每个命令字节在写的时候都是低字节先写,例如CCH的二进制为11001100,在写到总线上时要从低位开始写,写的顺序是“0、0、1、1、0、0、1、1”,整个操作的总线状态如图所。


2、读取RAM的温度数据,同样,这个操作也要按照三个步骤:

a -- 主机发出复位操作并接受DS18B20的应答(存在)脉冲;
b -- 主机发出跳过对ROM操作的命令(CCH);
c -- 主机发出读取RAM的命令(BEH),随后主机依次读取DS18B20发出的从第0-第8,共九个字节的数据。如果只想读取温度数据,那在读完第0和第1个数据后就不再理会后面DS18B20发出的数据即可,同样读取数据也是低位在前,整个操作的总线状态如图所示。

三、具体驱动编写

1、ds18b20_drv.c

[cpp] view plaincopy
  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");

2、app-ds18b20.c

[cpp] view plaincopy
  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. }

测试结果:

[cpp] view plaincopy
  1. [root@www.linuxidc.com home]#
  2. [root@www.linuxidc.com 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. [root@www.linuxidc.com home]#

DS18B20 驱动编写相关推荐

  1. linux编写gpio驱动程序,linux driver ------ GPIO的驱动编写和调用

    判断哪些文件被编译进内核: 1.通过 make menuconfig 查看 2.比如查看gpio类型的文件,输入 ls drivers/gpio/*.o,有生成.o文件表示被编译进内核 在编写驱动程序 ...

  2. 设备树下的platform 驱动编写

    目录 设备树下的platform 驱动简介 硬件原理图分析 实验程序编写 修改设备树文件 platform 驱动程序编写 编写测试APP 运行测试 编译驱动程序和测试APP 运行测试 上一章我们详细的 ...

  3. Linux程序之触摸,linux 触摸屏驱动编写

    早在诺基亚手机还比较流行的时候,那时候触摸屏用的还不多.但是随着触摸屏手机.即智能手机的流行,触摸屏基本成了手机的标配.所以,今天可以看看触摸屏驱动在linux上是如何进行的. 1.驱动目录 driv ...

  4. linux设备驱动编写基础

    Linux设备驱动编写基础 一.linux中的驱动是以模块的形式存在的,这样就大大提高了驱动的灵活性,linux内核模块的程序结构如下: l  模块加载函数(必须):module_init() l  ...

  5. 编写android驱动程序,Android 驱动编写LED-NDK程序

    1. 首先编写LINUX内核模块LED #include #include #include #include #include #include #include #include MODULE_L ...

  6. linux驱动编写(入门)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在我离职之前,工作内容几乎不涉及到驱动方面的知识.我所要做的内容就是把客户对设备的请求拆分成一 ...

  7. ARM+SD2405 IIC_RTC驱动编写及IIC通讯协议

    IIC通讯协议 协议简介 IIC(inter-integrated Circuit集成电路总线)总线支持设备之间的短距离通信,用于处理器和一些外围设备之间的接口,它需要两根信号线来完成信息交换,它是由 ...

  8. Linux驱动编写入门-新解

    1.驱动编写后是一个C文件,通过make命令对其进行编译,生成 .KO文件,这个文件就是可执行的驱动文件,通过使用insmod xx.ko即可执行此驱动文件.如下为一个完整的驱动程序C文件.(用的是讯 ...

  9. IMX6ull_Linux驱动编写(1)

    IMX6ull_Linux驱动编写-1 linux系统下程序编写架构分析 前言 整体分析 驱动大致框架介绍 Makefile文件 运行流程测试 linux系统下程序编写架构分析 前言   Linux属 ...

最新文章

  1. pandas基于dataframe字符串数据列不包含特定字符串来筛选dataframe中的数据行(rows where values do not contain substring)
  2. 【 Vivado 】输出延迟约束(Constraining Ouput Delay)
  3. solidworks无法获得下列许可standard_SolidWorks2020安装无法获得下列许可SOLIDWORKS Standard怎么解决?...
  4. 【Mac】Mac下安装MySQL优化工具 percona-toolkit 报错 Error: Failed to download resource openssl@1.1
  5. 自动驾驶感知系统(图)侵删
  6. gulp安装指定版本_对比webpack,你更应该先掌握gulp【10分钟教你彻底掌握gulp】
  7. c语言系统关键词有哪些,C语言的那些关键字
  8. 台式计算机怎么关闭无线网络,台式机无线网卡被禁用了如何解决
  9. 移动端h5框架自适应_最佳移动端h5自适应rem适配方案
  10. 【哼歌检索】十大语音搜索应用服务
  11. Win7 开机后3分钟内硬盘等狂闪解决办法
  12. Android手机开启开发者选项(红米note7举例)
  13. 条形码生成软件如何制作A级条码
  14. 高斯消去法解线性方程组C++实现
  15. 苹果手机投影_智能手机投屏到投影仪
  16. C语言socket重连和心跳,c# socket 心跳 重连
  17. Fiddle 抓包小白一步带过超详细教程(含汉化)
  18. USACO 3.2 Sweet Butter 香甜的黄油
  19. 常用颜色的十六进制和rgb格式
  20. 2021年B证(安全员)考试APP及B证(安全员)实操考试视频

热门文章

  1. Window 通过cmd查看端口占用、相应进程、杀死进程等的命令【转】
  2. MySQL 读写分离 使用驱动com.mysql.jdbc.ReplicationDriver
  3. 网站决策分析软件WebBI
  4. 天凉了,大家多穿衣服
  5. 数据可视化 信息可视化_可视化数据以帮助清理数据
  6. 熊猫数据集_对熊猫数据框使用逻辑比较
  7. react 使用 mobx_如何使用React和MobX状态树构建基于状态的路由器
  8. freecodecamp_freeCodeCamp的新编码课程现已上线,其中包含1,400个编码课程和6个开发人员认证
  9. 捷克 签证_一位捷克开发人员构建了可在您的浏览器中直接运行的语音合成器
  10. [前端随笔][css] 弹性布局