本来这次想做LCD背光灯的调节的,但是没有调通,时间很紧迫,就转向了其它东西,昨天调了一下DHT11,今天又调了一下DS18B20,还算有个安慰,本来是想用1-wire子系统做的,但是时间上有点紧,要看源代码好长时间去领悟,所以,先自己用以前的笨方法先实现.

先来介绍一下DS18B20:

DS18B20 是由 DALLAS 半导体公司推出的一种的 “一线总线”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。一线总线结构具有简洁且经济的特点,可使用户轻松地组建传感器网络,从而为测量系统的构建引入全新概念,测量温度范围为-55~+125℃ ,精度为±0. 5℃。

现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。它能直接读出被测温度,并且可根据实际要求通过简单的编程实现 9~l2 位的数字值读数方式。它工作在3—5. 5 V 的电压范围,采用多种封装形式,从而使系统设计灵活、方便,设定分辨率及用户设定的报警温度存储在EEPROM 中,掉电后依然保存。其内部结构如图所示:

ROM 中的 64 位序列号是出厂前被光记好的,它可以看作是该 DS18B20 的地址序列码,每个DS18B20 的 64 位序列号均不相同。 64 位 ROM 的排列是:前 8 位是产品家族码,接着 48 位是DS18B20 的序列号,最后 8 位是前面 56 位的循环冗余校验码(CRC=X8+X5+X4 +1)。 ROM 作用是使每一个 DS18B20 都各不相同,这样就可实现一根总线上挂接多个。

所有的单总线器件要求采用严格的信号时序,以保证数据的完整性。 DS18B20 共有 6 种信号类型:复位脉冲、应答脉冲、写 0、写 1、读 0 和读 1。所有这些信号,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。这里我们简单介绍这几个信号的时序:

1).复位脉冲和应答脉冲

单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少 480us,以产生复位脉冲。接着主机释放总线,4.7K 的上拉电阻将单总线拉高,延时 15~60 us,并进入接收模式(Rx)。接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,若为低电平,再延时 480 us。

2 )  写时序

写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2 次独立的写时序之间至少需要 1us 的恢复时间,两种写时序均起始于主机拉低总线。写 1 时序:主机输出低电平,延时 2us,然后释放总线,延时 60us。写 0 时序:主机输出低电平,延时 60us,然后释放总线,延时 2us。

3 )读时序  
    单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的 15us 之内采样总线状态。典型的读时序过程为:主机输出低电平延时 2us,然后主机转入输入模式延时 12us,然后读取单总线当前的电平,然后延时 50us。

在了解了单总线时序之后,我们来看看 DS18B20 的典型温度读取过程, DS18B20 的典型温度读取过程为:

复位-->发 SKIP ROM 命令(0XCC)-->发开始转换命令(0X44)-->延时-->复位-->发送 SKIP ROM 命令(0XCC)->发读存储器命令(0XBE)-->连续读出两个字节数据(即温度)-->结束。DS18B20 的介绍就到这里,更详细的介绍,请大家参考 DS18B20的数据手册

下面,来讲一下驱动的设计思路:

1).DS18B20的初始化

初始化时序图;

设计分析:

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

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

初始化代码;

/* 1.复位信号 */
void DS18B20_Rst(void)
{gpio_request(DQ_IN_GPIO, "DQ_OUT");gpio_direction_output(DQ_IN_GPIO, 0);udelay(750);     //拉低750usgpio_direction_output(DQ_IN_GPIO, 1);udelay(15);           //拉高15usgpio_free(gpio_get_value(DQ_IN_GPIO));
}

DS18B20 写操作

主机发出各种操作命令都是向DS18B20写0和写1组成的命令字节, 接收数据时也是从DS18B20读取0或1的过程。因此首先要搞清主机是如何进行写0、写1、读0和读1的。

写周期最少为60微秒,最长不超过120微秒。写周期一开始做为主机先把总线拉低1微秒表示写周期开始。随后若主机想写0,则将总线置为低电平,若主机想写1,则将总线置为高电平,持续时间最少 60微秒直至写周期结束,然后释放总线为高电平至少1微秒给总线恢复。而DS18B20则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0 。

写数据代码:

/* 3.写时序,一个字节 */
void DS18B20_Write_Byte(int dat)
{int j,testb;gpio_request(DQ_IN_GPIO, "DQ_OUT");for(j = 0; j < 8; j++){testb = dat & 0x1;dat >>= 1;if(testb){  // 写1时序gpio_direction_output(DQ_IN_GPIO, 0);             udelay(2);gpio_direction_output(DQ_IN_GPIO, 1);udelay(60);} else {    // 写0时序gpio_direction_output(DQ_IN_GPIO, 0);udelay(60);gpio_direction_output(DQ_IN_GPIO, 1);udelay(2);}}gpio_free(DQ_IN_GPIO);
}

DS18B20 读操作

对于读数据操作时序也分为读0时序和读1时序两个过程。读周期是从主机把单总线拉低1微秒之后就得释放单总线为高电平,以让DS18B20把数据传输到单总线上。作为从机DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束。若要送出1则释放总线为高电平。主机在一开始拉低总线1微秒后释放总线,然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为0 。采样期内总线为高电平则确认为1。完成一个读时序过程,至少需要60微秒才能完成。

/* 4.读一bit数据 */
int DS18B20_Read_Bit(void)
{int data;gpio_request(DQ_IN_GPIO, "DQ_OUT");gpio_direction_output(DQ_IN_GPIO, 0);udelay(2);gpio_direction_output(DQ_IN_GPIO, 1);udelay(12);// gpio_free(DQ_IN_GPIO);// gpio_request(DQ_IN_GPIO, "DQ_IN");gpio_direction_input(DQ_IN_GPIO);if(gpio_get_value(DQ_IN_GPIO))data = 1;elsedata = 0;udelay(50);gpio_free(DQ_IN_GPIO);return data;
}/* 5.读一个字节的数据 */
int DS18B20_Read_Byte(void)
{int i, j, dat = 0;for(i = 0; i < 8; i++){j = DS18B20_Read_Bit();//低位先行,j左移7位,把最低位赋给dat,同时dat左移1位,把低位右移,循环8次你懂的dat = (j << 7) | (dat >> 1);}return dat;
}

DS18B20 的寄存器简介
1.   DS18B20  内部结构主要由四部分组成:  
1), 64  位光刻  ROM光刻ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码。64 位光刻ROM的排列是:开始8位(地址:28H)是产品类型标号,接着的48位是该DS18B20自身的序列号,并且每个DS18B20的序列号都不相同,因此它可以看作是该DS18B20的地址序列码;最后8位则是前面56位的循环冗余校验码(CRC=X8+X5+X4+1)。由于每一个DS18B20的ROM数据都各不相同,因此微控制器就可以通过单总线对多个DS18B20进行寻址,从而实现一根总线上挂接多个DS18B20的目的。
2), 温度传感器  
3), 非挥发的温度报警触发器TH和TL
4), 配置寄存器。

2. DS18B20的存储器由一个高速暂存RAM和一个非易失性、 电可擦除(E2)RAM组成.

我们看一下第4个字节,配置寄存器:

出厂设置默认R0和R1都配置为1,也就是温度计分辨率是12bit.

1.8  读取温度操作  
1.  读取温度操作  
     DS18B20  经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。所以当我们只想简单的读取温度值的时候,只用读取暂存器中的第0和第1个字节就可以了。读取一次D18B20温度的操作步骤  如下:  
a)  初始化DS18B20
b)  跳过ROM操作(ROM里面可以读取DS18B20的地址、型号,还有  配置分辨率等,我们只使用一个DS18B2,所以不用读取地址型号,配置直接使用默认的12位分辨率就好了.  
c)  发送温度转换命令。  
d)  跳过ROM操作  
e)  发送读取温度命令

f)  读取温度值。

2   补码介绍
什么是补码  
a)  正数的补码是正数本身 
b)  负数的补码是原码取反,然后再加 1。DS18B20存储的温度值是以补码的形式存储的,所以读出来的温度值是实际温度值的补码,要把的转换为原码。

1)正温度的话,原码就是补码本身,所以在12位分辨率下,温度的计算公式是:

温度值=读取值*0.0625

2)负温度的话,原码是补码减1再取反,所以在12位分辨率下,计算公式为:

温度值= -(读取值取反再加1)*0.0625

/* 7.处理温度信息 */
int DS18B20_Get_temp(void)
{int tem = 0,TL  = 0, TH  = 0;DS18B20_Start();DS18B20_Rst();DS18B20_CheckAck();DS18B20_Write_Byte(0xcc);DS18B20_Write_Byte(0xbe);TL = DS18B20_Read_Byte();TH = DS18B20_Read_Byte();if(TH > 7){TH = ~TH;TL = ~TL;temp = 0;}else{temp = 1;}tem = TH;tem <<= 8;tem += TL;/*** 内核不支持浮点运算,如果在内核里做计算会丢失小数部分* 所以计算留给用户程序来完成,这里直接传输原始数据即可*/ if(temp){return tem;}elsereturn ~tem + 1;
}

下面来一个完整的驱动代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>#include <asm/io.h>
#include <asm-generic/uaccess.h>
#include <linux/delay.h>#include <mach/gpio.h>#define DQ_IN_GPIO      EXYNOS4_GPX3(2)     // 操作DS18B20的GPIO/*********************************************DS18B20************************************************/
/* 1.复位信号 */
void DS18B20_Rst(void)
{gpio_request(DQ_IN_GPIO, "DQ_OUT");gpio_direction_output(DQ_IN_GPIO, 0);udelay(750);     //拉低750usgpio_direction_output(DQ_IN_GPIO, 1);udelay(15);           //拉高15usgpio_free(gpio_get_value(DQ_IN_GPIO));
}/* 2.应答信号 */
int DS18B20_CheckAck(void)
{int retry = 0;gpio_request(DQ_IN_GPIO, "DQ_IN");gpio_direction_input(DQ_IN_GPIO);while(gpio_get_value(DQ_IN_GPIO) & (retry < 200)){retry++;udelay(1);};if(retry >= 200){gpio_free(gpio_get_value(DQ_IN_GPIO));return -1;}retry = 0;while(!gpio_get_value(DQ_IN_GPIO) & (retry < 240)){retry++;udelay(1);}if(retry >= 240){gpio_free(gpio_get_value(DQ_IN_GPIO));return -1;}gpio_free(gpio_get_value(DQ_IN_GPIO));return 0;
}/* 3.写时序,一个字节 */
void DS18B20_Write_Byte(int dat)
{int j,testb;gpio_request(DQ_IN_GPIO, "DQ_OUT");for(j = 0; j < 8; j++){testb = dat & 0x1;dat >>= 1;if(testb){  // 写1时序gpio_direction_output(DQ_IN_GPIO, 0);             udelay(2);gpio_direction_output(DQ_IN_GPIO, 1);udelay(60);} else {    // 写0时序gpio_direction_output(DQ_IN_GPIO, 0);udelay(60);gpio_direction_output(DQ_IN_GPIO, 1);udelay(2);}}gpio_free(DQ_IN_GPIO);
}/* 4.读一bit数据 */
int DS18B20_Read_Bit(void)
{int data;gpio_request(DQ_IN_GPIO, "DQ_OUT");gpio_direction_output(DQ_IN_GPIO, 0);udelay(2);gpio_direction_output(DQ_IN_GPIO, 1);udelay(12);// gpio_free(DQ_IN_GPIO);// gpio_request(DQ_IN_GPIO, "DQ_IN");gpio_direction_input(DQ_IN_GPIO);if(gpio_get_value(DQ_IN_GPIO))data = 1;elsedata = 0;udelay(50);gpio_free(DQ_IN_GPIO);return data;
}/* 5.读一个字节的数据 */
int DS18B20_Read_Byte(void)
{int i, j, dat = 0;for(i = 0; i < 8; i++){j = DS18B20_Read_Bit();//低位先行,j左移7位,把最低位赋给dat,同时dat左移1位,把低位右移,循环8次你懂的dat = (j << 7) | (dat >> 1);}return dat;
}/* 6.温度转换 */
void DS18B20_Start(void)
{DS18B20_Rst();DS18B20_CheckAck();DS18B20_Write_Byte(0xcc);DS18B20_Write_Byte(0x44);
}/* 7.处理温度信息 */
int DS18B20_Get_temp(void)
{int tem = 0,TL  = 0, TH  = 0;DS18B20_Start();DS18B20_Rst();DS18B20_CheckAck();DS18B20_Write_Byte(0xcc);DS18B20_Write_Byte(0xbe);TL = DS18B20_Read_Byte();TH = DS18B20_Read_Byte();if(TH > 7){TH = ~TH;TL = ~TL;temp = 0;}else{temp = 1;}tem = TH;tem <<= 8;tem += TL;/*** 内核不支持浮点运算,如果在内核里做计算会丢失小数部分* 所以计算留给用户程序来完成,这里直接传输原始数据即可*/ if(temp){return tem;}elsereturn ~tem + 1;
}
/*****************************************************************************************************/int
ds18b20_open(struct inode *inode, struct file *filp)
{// 硬件初始化/*do nothing*/return 0;
}ssize_t
ds18b20_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{int ret = -1,temp_buf;temp_buf = DS18B20_Get_temp();ret = copy_to_user(buf, &temp_buf, count);if(ret > 0){printk("copy to user failed !\n");return -EFAULT;}return count;
}int
ds18b20_release(struct inode *inode, struct file *filp)
{// 释放引脚gpio_free(DQ_IN_GPIO);return 0;
}const struct file_operations ds18b20_fops = {.open   = ds18b20_open,.read   = ds18b20_read,.release= ds18b20_release,
};struct miscdevice ds18_misc = {.minor  = MISC_DYNAMIC_MINOR,.name   = "ds18b20",.fops   = &ds18b20_fops,
};static void __exit
ds18b20_drv_exit(void)
{misc_deregister(&ds18_misc);
}static int __init
ds18b20_drv_init(void)
{// 注册杂项设备,因为比直接的普通字符设备少写好多代码int ret = misc_register(&ds18_misc);if(ret < 0){printk("misc register failed !\n");return -EINVAL;}return 0;
}module_init(ds18b20_drv_init);
module_exit(ds18b20_drv_exit);MODULE_LICENSE("GPL");

然后是测试代码;

#include <stdio.h>
#include <stdlib.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(void)
{int fd = -1,temp= 0,a = 0;fd = open("/dev/ds18b20", O_RDWR);if(fd < 0){perror("open failed");exit(1);}for(;;){read(fd, &temp, sizeof(temp));a = (float)temp * 0.625;if(a > -551 && a < 1251)printf("<APP> temp: %d.%d C\n", a / 10, a % 10);sleep(2);}if(close(fd) < 0){perror("close failed");exit(3);}return 0;
}

然后是Makefile:

#指定内核源码路径
KERNEL_DIR = /home/george/1702/exynos/linux-3.5#指定当前路径
CUR_DIR = $(shell pwd)MYAPP = w1_ds18b20_app
MODULE = w1_ds18b20all:make -C $(KERNEL_DIR) M=$(CUR_DIR) modulesarm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c
clean:make -C $(KERNEL_DIR) M=$(CUR_DIR) clean$(RM) $(MYAPP)
install:cp -raf *.ko $(MYAPP) /home/george/1702/exynos/filesystem/1702#指定编译当前目录下那个源文件
obj-m = $(MODULE).o

附一张测试效果图:

第1次显示的85℃是正常的,是初始化信息,其它两次58.3℃和90.8℃是不正常的,但是大多数数据都是OK的,大概的原因可能是我这个传感器是外接的,友善之臂真扣,连个DS18B20都不带,外接的接触不良或者有干扰可能会造成这种情况.好了先写到这里吧.

⑨tiny4412 Linux驱动开发之1-wire子系统(DS18B20)驱动程序相关推荐

  1. ⑭tiny4412 Linux驱动开发之cpufreq子系统驱动程序

    本次我们来说一下CPU动态调频子系统. 首先来看一下三星Exynos 4412的datasheet,如下: 上图就是Exynos 4412的时钟分布图,可以看到CPU的频率可以在1.4GHz~200M ...

  2. linux 串口驱动 4412,⑮tiny4412 Linux驱动开发之tty子系统(UART)驱动程序

    本次说一下tty子系统的驱动编程,因为UART相关的寄存器比较多,同时,应用比较广泛,所以本次的驱动程序量也不少,而且只是完成和特定CPU相关的一部分,通用的部分本次都没有涉及到.在写驱动之前,我们先 ...

  3. Linux驱动开发之platform设备驱动实验【完整教程】

    为了方便驱动的编写,提高软件的重用性和跨平台性能,于是就提出了Linux驱动的分离和分层   驱动的分层,分层的目的时为了在不同的层处理不同的内容,最简单的驱动分层是input子系统负责管理所有跟输入 ...

  4. ㉕AW-A33 Linux驱动开发之audio子系统驱动程序

    在Linux源码里,Aduio这一部分现在是一个独立文件夹叫sound,在2.x的版本时,sound这个目录是在drivers里的,后来从这个里面剥离出来了,很多人不知道其中的原因,我也不知道,我们先 ...

  5. linux编译input驱动,Linux驱动开发之input子系统

    本文对mousedev.Amimouse和input子系统进行分析,旨在提纲挈领,给出它们之间的调用关系(或者说关联).阅读本文,需要与阅读Linux 2.6内核源码交叉进行,除非你是超人. 背景: ...

  6. ㉓AW-H3 Linux驱动开发之mipi camera(CSI)驱动程序

    本次说一下mipi camera的驱动开发,平台用的是全志的H3芯片,项目代号:sun8iw7p1,这次使用运行在H3上面的Ubuntu进行验证的. Linux代码:https://github.co ...

  7. Linux驱动开发之DRM驱动

    作者 QQ群:852283276 微信:arm80x86 微信公众号:青儿创客基地 B站:主页 https://space.bilibili.com/208826118 参考 Linux DRM Gr ...

  8. ㉔AW-H3 Linux驱动开发之HDMI驱动程序

    HDMI: High Definition Multimedia Interface,高清多媒体接口,是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号.HDMI有4种类型的接口,分别为 ...

  9. linux驱动开发之spi-omap-100k.c源码分析

    代码分析 对于linux的驱动代码来说,我们要从后往前分析: /** OMAP7xx SPI 100k controller driver* Author: Fabrice Crohas <fc ...

最新文章

  1. 洛谷 P2746 [USACO5.3]校园网Network of Schools
  2. MySQL 慢查询日志工具之pt-query-digest
  3. c语言求上升沿次数,[求助]上升沿信号在C语言中怎么写啊
  4. AR与大数据 珠联璧合带来的无限想象空间
  5. oracle指定源位置怎么弄,ORACLE Goldengate测试解决源端和目标端表结构字段位置不同的2种实现方法...
  6. java对象与c网络语言通信,JAVA与C语言的网络通信代码案例.pdf
  7. cordova报错“No installed build tools found. Install the Android build tools version - ”
  8. hihoCoder 1080 : 更为复杂的买卖房屋姿势 线段树区间更新
  9. 爬虫-----自定义框架
  10. 「项目分享」软件测试简历中项目怎么写?从候选人中脱颖而出,offer拿到手软
  11. 带分页存储管理系统中计算机应用自考,自考计算机应用基础试题及答案
  12. selenium定位到元素后获取其属性_selenium定位tr及td,并获取其文本及属性
  13. 海康ISAPI透传ftp
  14. 计算机文件云同步,电脑文件夹同步
  15. 冲刺!这篇 1658 页的《Java 面试突击核心讲》学明白保底年薪 30w
  16. 微软认证(dynamic 365)考试
  17. Python基础教程让小白从入门到精通(一)爬虫分析
  18. VS2019程序打包(带sql sever转access数据库)
  19. linux小型游戏系统设计,Linux平台下基于JAVA小游戏_设计文档.doc
  20. jvm crash分析

热门文章

  1. zenmap使用教程
  2. OAI搭建之SIM卡
  3. SpringBoot项目实战:员工管理系统
  4. 《数据结构课程实践》_02_隐式图的搜索问题_准备工作
  5. GPS卫星定位系统与手机窃听原理
  6. 【几种特殊的矩阵:对角矩阵、上下三角矩阵、正态分布随机矩阵、魔方矩阵、希尔伯特矩阵、托普利兹矩阵】
  7. 上班拍抖音需谨慎!Tiktok「科技网红」因自拍泄密被苹果解雇
  8. SAAS 客服云平台市场调研报告
  9. CSS中的滑动门技术
  10. 最近的热门:渣打小三事件