一种快速查询多点DS18B20温度的方法(转)
源:http://hi.baidu.com/james_xiao/item/79b961c90623093e45941623
一种快速查询多点DS18B20温度的方法
引言
为了满足实时性要求较高系统的设计需求,针对串联多个器件在一线制总线上的结构导致的在查询多点温度时速度缓慢的问题,北京铭正同创科技有限公司提出了一种快速查询多点温度的解决方案。本方案以Dallas公司开发的一线制数字温度传感器DS18B20为核心,通过采用每个并行端口上连接一个DS18B20器件,实现同时对多个DS18B20进行同步操作的方法。本方案可广泛应用于各种工业控制、仪器仪表产品中。
关键字快速多点温度查询 工业控制 仪器仪表 铭正同创
1 技术概述
Dallas公司开发的一线制数字温度传感器DS18B20是一款性能优异的数字式传感器,广泛应用于各种工业控制、仪器仪表产品当中。DS18B20与传统的热敏电阻温度传感器相比,能够直接读出被测温度,并且根据实际要求通过简单的编程可设置9~12位的分辨率,可以在750ms内将温度转化为12位的数字量,具有多种可选的封装方式。因而使用DS18B20可使系统结构更加简单,可靠性更高。DS18B20器件具体的封装形式如下图所示:
GND 接地
DQ 一线制总线(输入/输出)
VD 供电电源 而DS18B20的一线制总线独特而经济的特点,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。一般应用一线制总线对DS18B20进行多点温度监控时,多采用如下的电路形式,即在一DQ线上串接多个DS18B20器件。如下图:
在一线制总线上串接多个DS18B20器件时,实现对其中一个DS18B20器件进行一次温度转换和读取操作主要包括以下13个步骤(所有的操作都是通过DQ线进行信号传输的):
1 主机MCU发复位脉冲
2 DS18B20发应答脉冲(即MCU接收该应答信号,以确认器件在总线上)
3 主机发匹配ROM命令
4 主机发64位器件序列号(器件序列号与总线上的某个DS18B20器件一一对应)
5 主机发温度转换指令
6 总线保持高电平50ms
7 主机发复位命令
8 DS18B20发应答脉冲
9 主机发匹配ROM命令
10 主机发64位器件代码
11 主机发读数据寄存器指令
12 主机接收数据
13 主机发复位脉冲
参考DS18B20的数据手册可知,当DS18B20的精度设置为12位精度表示时,依据上面的步骤完成对一个器件的测温、读取温度值的过程,大概会消耗掉1秒钟的时间。而如果总线上存在8个DS18B20器件的话,完成一次8个器件的查询需要8秒的时间,这不还没计算在系统初始化时,对总线上的器件序列号进行初始化过程所消耗的时间。
针对所述利用多个DS18B20器件串接在一线制总线上进行多点温度查询时速度慢的原因,做进一步分析如下。
DS18B20器件在进行一线制总线操作时,仅有一根DQ线用于双向的数据传输,每一个操作最小的细分至每一个的读写过程,即一个位的读写操作为一线制总线操作的最小单位,可以参考DS18B20的手册,了解到每一次最小单位的总线操作利用了规定时间内MCU驱动DQ线的高低电平来决定读/写的操作,然后在其后的规定时间内完成读/写一个位数据的操作。这样,就决定了每一次操作的过程中,要传输的数据位数越多,每一次的操作耗时越长。而DS18B20的一线制总线的操作对时序的要求很严格,一般在设计MCU对其总线操作的程序时,都是利用延时去保证每个读写周期的时间准确性,即说明这些时间内CPU必然是闲置的。如下图示意了一个写0和1操作的时序:
另外,在多个器件串接在一线制总线上时,为了区分每次操作是针对总线上哪一个器件,DS18B20器件在内部提供了每个器件独有的64位ROM序列号,也就是说每一次操作都要首先在对DS18B20器件的ROM序列号进行匹配后,方可对其中的某一个器件进行测温/读取温度值的操作。可以估算出,每一次序列号的匹配操作,差不多需要4ms的时间,完成一次完整的测温/读取温度值操作,就需要进行两次序列号匹配,即消耗掉大概8个ms的时间。
多个器件串接在总线上时,对所有的器件的查询操作,需要一个一个来,完成一次全部器件的查询需要成倍的操作时间,整个系统把大量时间消耗在时序所要求的延时上。
此外,当采用多个器件串接在一线制总线的系统时,还需要在系统的初始化其间花销较长的时间来进行烦琐的总线上器件的序列号查询,并以此获知总线上的每个器件的序列号。
如前所述,可以总结出,影响查询多点DS18B20温度速度的最主要因素有如下几个:
1.每次操作都需要附加两次对64位序列号的匹配过程;
2.多个器件串接,完成全部的查询就需要与器件个数成倍增长的耗时。
这样的应用在一些对实时性要求相对较高的系统当中,是非常占用资源的(虽然省掉了端口资源,但CPU不得不等待N长时间后方可获取多点的温度值),所以使用起来总会有些遗憾。下面,介绍一种快速查询多点DS18B20温度的方法,包括硬件的连线构成以及软件的编程思路。
2 解决方案
由于一般都会将对DS18B20器件的温度查询放置在中断当中实现或者是在程序的主循环当中采用定时查询的方法实现,所以这就要求每次对DS18B20的操作都能快速的完成,尽快退出来进行其它的处理。所以为了解决串联多个器件在一线制总线上的结构导致的在查询多点温度时速度缓慢的问题,本设计提出一种解决方案,具体说是通过修改硬件连接来实现方便快捷的查询多点DS18B20器件温度的方法。
2.1 快速查询多点DS18B20温度的方法简述
当一线制总线上仅有一个DS18B20器件时,可以用skip ROM操作(即跳过ROM匹配)命令来代替64位序列号的匹配过程,这点也是使用单个DS18B20器件的系统常用的方法。所以,要想节省掉64位序列号匹配的时间开销,就必需设计成一个一线制总线上仅有一个DS18B20器件的系统。
DS18B20的一线制总线在时序上的严格要求,也从另一方面意味着在一定的弹性范围内,不同DS18B20器件的时序细节上的一致性应该是非常好,所以可以将系统设计成利用MCU的并行端口同时对多个DS18B20进行统一的操作,不过这时候并行端口上的每一个端口连接着一个DS18B20器件而已。
本文所述的解决方案正是以端口的消耗为代价,换取对多点DS18B20温度查询的速度,并在程序结构的设计上采用一些巧妙的处理方法,使得系统对DS18B20的操作上花更少的时间。此外,采用本设计实现的快速多点温度查询系统,可以省掉烦琐的总线上器件序列号的查询操作,并可节省大量的存储空间(原用于存储总线上器件的序列号所用的空间)。
从理论上分析,本设计方案的采用,查询多个DS18B20器件操作所消耗的时间与查询一个DS18B20器件操作所消耗的时间是等量的。
下面以查询8个DS18B20器件为例详细分析此方法的设计思想。
2.2 系统硬件连接
本系统方案8个DS18B20器件连接在MCU的一组端口的8个I/O口上,连线示意图如下所示:
当然,上图中的示意图并没有考虑诸如端口驱动能力、抗干扰处理等,仅表明一个逻辑的连接示意,具体在产品级的设计时会根据产品的应用做必要的处理,比如增加一些必要的电路等,此处不作为讨论的重点。
从上图可见,每个端口连接有一个DS18B20器件,也即一条一线制总线上仅有一个DS18B20器件,符合了前面所述的解决方法。实际在对DS18B20器件进行操作时,只需统一地对这一组并行端口进行操作(每个端口在同一时间输出相同的电平状态)即可。
一个端口对应一个DS18B20器件,也就表示每组端口的某一个位的读回数据状态也就是该端口所对应的器件的输出状态,所以,这样的系统里面是不需要进行每个器件的序列号搜索、匹配的操作的。可知,在对DS18B20器件进行操作时,可以使用skip ROM命令来跳过ROM序列号匹配的操作,也即在所有的DS18B20器件的ROM操作时可以使用相同的端口输出时序。
2.3 软件设计思路
总结前面所介绍的电路示意图,下面详细介绍程序设计思想。
在接下来的软件介绍中,会以C语言的例子介绍具体的编程思路,但这些代码并非就是实际中所使用的代码,仅作为逻辑性的参考,以便大家理解。这些代码是从一个产品的应用当中摘出的,而程序设计的结构也是从具体的设计当中分解出来的,供大家参考。
软件设计从最底层的与DS18B20时序相关的驱动,到与一线制总线器件处理过程控制/协议的接口函数,再上升到应用API接口函数的关系如下图所示:
在对连在一组8位端口上的8个DS18B20操作时,是同时对该组端口进行操作,也即同时对8个DS18B20器件进行同步的操作。
范例程序是根据笔者的项目当中的功能需求而设计的,不一定会适合所有人的使用方法,但程序设计思想是可以参考的,这点请使用者在参考本文时对这里的范例进行一定的取舍。下面详细介绍一个以MCS51系列单片机的应用为例的范例程序,其中约定与8个DS18B20器件进行连接的是P1端口。
2.3.1 底层时序驱动
底层时序驱动程序与DS18B20的一线制总线的协议保持一致,根据一线制总线时序的特点,设计了四个基本的函数:
总线写1时序控制函数:
void DS18B20_Write_1(void)
{
P1 = 0x00; //8个DQ 线全部设置为低电平
Delay_1us(10); //延时10us左右
P1 = 0xff; //8个DQ线全部输出高电平
Delay_1us(30); //延时30us左右
}
总线写0时序控制函数:
void DS18B20_Write_0(void)
{
P1 = 0x00; //8个DQ 线全部设置为低电平
Delay_1us(40); //延时
P1 = 0xff; //端口恢复高电平
Delay_1us(1);
}
总线读取一个数据位时序控制函数:
unsigned char DS18B20_ReadDQ(void)
{
unsigned char DQ_S=0;
P1 = 0x00; //8个DQ 线全部设置为低电平
Delay_1us(10);
P1 = 0xff; //端口置1,准备读取
Delay_1us(1); //延时待总线准备好数据
DQ_S = P1; //一次性读取8条DQ线的数据状态
P1 = 0xff; //恢复端口电平
Delay_1us(30); //延时
return DQ_S; //返回读取的值
}
在读取一个总线状态数据位的函数中,将会返回一个byte的数据,该数据的8个位正好与连接在P2端口上的8个I/O口对应,如下图所示:
总线复位时序控制函数:
void DS18B20_Reset(void)
{
unsigned char Error_Counter=0;
P1 = 0x00; //8个DQ 线全部设置为低电平
Delay_1us(500); //保持总线低电平500us
P1 = 0xff;
Delay_1us(100);
if(P1!=0x00) B20_Error = P1;//如检测到DS18B20总线响应了回复信号,则读取当前8条
//总线的状态
Delay_1us(50);
P1 = 0xff;
for(Error_Counter=0;Error_Counter<200;Error_Counter++)
{
if((P1&(~B20_Error))==(~B20_Error)) break; //如检测到总线的回复信号结
//束,则退出循环
Delay_1us(1);
}
P1 = 0xff; //恢复端口电平
Delay_1us(200); //延时 200us~~~
}
在复位时序控制的函数中,使用了B20_Error全局变量,它将会传递给上一层的数据处理函数作为判断当前8个I/O口所接的DS18B20是否正常工作,或者是否在各自的总线上。
2.3.2 操作协议相关的函数
分析DS18B20的一线制总线控制命令,可以提炼出两个最基本的操作函数,一个是写一个byte数据至DS18B20器件,另一为读取DS18B20器件的数据。而在本文的范例程序当中,仅仅为了提取DS18B20器件的转换完后的温度值,所以在读取DS18B20的数据时,仅读取存放在数据地址前两个字节的温度数据,而不读取其它字节的数据,包括CRC校验值也没有进行读取,供参考。
写字节操作函数:
void DS18B20_WriteByte(unsigned char Com)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(Com&0x01)
DS18B20_Write_1();
else
DS18B20_Write_0();
Com = Com>>1;
}
}
调用DS18B20_WriteByte函数,连在8个I/O口上的一线制总线上的8个DS18B20器件,将都会接收到同样的一个字节的数据:Com。
读数据操作函数:
unsigned char Read_buf_8ch[16]; //buffer of Read DS18B20
void DS18B20_Read2Byte(void)
{
unsigned int i;
for(i=0;i<16;i++)
{
Read_buf_8ch = DS18B20_ReadDQ();
}
}
前面已经介绍过了,在本范例中,只读取位到DS18B20内部数据区域的前两节字的温度值数据,所以数据读取函数设计成读取两个字节的函数,即需要连续读取16个位(对应于每一个DS18B20器件来说是连续的16个位)。而将读回的数据保存于一个Read_buf_8ch(简写:Rb)的数组中,可以根据系统的接线图对读回的16个字节的数据进行分析,如下图所示:
读取DS18B20的数据时,先读高位再读低位;所以可以从上图看到,以TM2的DS18B20的数据为例,TM2的两个字节的数据由Read_buf_8ch数组的16个字节数据中的每个字节的bit2位组成。可知,完成一次数据读取的操作后,可以同时读回8个DS18B20器件的数据,在数据处理时,只需针对上图的数据结构对Read_buf_8ch数组的数据进行处理即可得到每个DS18B20器件的测温值。
2.3.3 API功能函数:
供上层应用程序直接调用的函数相对来说,是与系统的具体硬件接法没有太多的关系,只需要依照DS18B20器件的操作流程进行操作即可。在此,提供两个API的范例,分别是启动温度转换控制函数和读取温度值函数。
启动温度转换控制函数:
void DS18B20_Conver(void)
{
DS18B20_Reset();
DS18B20_WriteByte(0xcc); //Skip ROM
DS18B20_WriteByte(0x44); //启动测温
}
读取温度值函数:
void DS18B20_ReadTemp(void)
{
DS18B20_Reset();
DS18B20_WriteByte(0xcc); //Skip ROM
DS18B20_WriteByte(0xbe); //送入读取数据命令
DS18B20_Read2Byte();
}
调用读取温度值函数后,8个DS18B20器件的测温数据将保存在数组Read_buf_8ch的16个字节单元当中,还有待进行下一步的处理,方可得到对应每个DS18B20器件的测温值。下面介绍简单的处理代码片断:
char i,j;
unsigned int uiData[8];
unsigned char Mask;
//OS the resoult of Temperature
for(i=15;i>=0;i--)
{
Mask = 0x01;
for(j=0;j<8;j++)
{
uiData[j] = uiData[j]<<1;
if(Read_buf_8ch&Mask) uiData[j]++;
Mask = Mask<<1;
}
}
经过上述简单的处理,8个DS18B20器件的测温数据将保存在数组uiData当中的8个单元里,就可以根据自身程序设计的需求来对这些数据进行具体的处理了。
3 结语
本文介绍的快速查询多点DS18B20温度的设计方案,解决了串联多个器件在一线制总线上的结构导致的在查询多点温度时速度缓慢的问题,基本的设计思想是:将系统设计为在每个并行端口上连接一个DS18B20器件,利用MCU的并行端口同时对多个DS18B20进行统一的操作,实现操作多个DS18B20器件的时间等同于操作单个DS18B20器件的时间。本设计思想,可以大大减少在查询多个DS18B20测温值的时间开销,满足了实时性要求较高的系统的设计需求;同时,也省掉了烦琐的总线上多个器件序列号搜索的代码的步骤,并且节省了用于存储这些器件的序列号的存储单元,使得利用DS18B20进行多点测温的操作变得更方便、容易。
虽然本文介绍的方法是以牺牲端口资源为代价,但具体在进行系统设计时,也可以通过一些扩展端口、串转并端口、多路模拟开关等硬件电路设计来弥补这些端口资源的消耗,也可通过这些硬件电路来扩展更多的DS18B20器件(如果有必要的话)。
本文所介绍的方法已经在笔者参与设计的大型恒温系统当中应用,目前系统运行稳定、可靠
一种快速查询多点DS18B20温度的方法(转)的更多相关文章
- Sublime Text 2/3 安装Emmet(Zencoding)以及常见使用,一种快速编写HTML/CSS代码的方法
原文链接http://blog.csdn.net/shirley254/article/details/52336744
- [笔记] 一种快速求 1 ~ n 逆元的方法
我们现在要求1~n在mod m意义下的逆元(n<m,m为素数). 对于一个[1,n]中的数i,我们令\(k=\lfloor\frac{m}{i}\rfloor,r=m \ mod \ i\) 然 ...
- 用DOM解析XML ,用xpath快速查询XML节点
XPath是一种快速查询xml节点和属性的一种语言,Xpath和xml的关系就像是sql语句和数据库的关系.用sql语句可以从数据库中快速查询出东西同样的用xPath也可以快速的从xml中查询出东西. ...
- 如何:使用TreeView控件实现树结构显示及快速查询
本文主要讲述如何通过使用TreeView控件来实现树结构的显示,以及树节点的快速查找功能.并针对通用树结构的数据结构存储进行一定的分析和设计.通过文本能够了解如何存储层次结构的数据库设计,如何快速使用 ...
- mysql 常用 sql 语句 - 快速查询
Mysql 常用 sql 语句 - 快速查询 1.mysql 基础 1.1 mysql 交互 1.1.1 mysql 连接 mysql.exe -hPup ...
- 可视化查询(sp_helptext)——快速查询包含指定字符串的存储过程(附源码)
前言 在开发中,随着业务逻辑的调整,修改存储过程是必不可免的. 那怎么定位到需要修改的存储过程呢?一个一个的点开查询?存储过程少的话还行,一旦存储过程过多,这样是很浪费时间的,一个不注意还会遗漏掉. ...
- linux几种快速清空文件内容的方法
linux几种快速清空文件内容的方法 几种快速清空文件内容的方法: $ : > filename #其中的 : 是一个占位符, 不产生任何输出. $ > filename $ echo & ...
- Django models .all .values .values_list 几种数据查询结果的对比
Django models .all .values .values_list 几种数据查询结果的对比
- 快速查询Python脚本语法
/********************************************************************* * 快速查询Python脚本语法 * 说明: * Char ...
随机推荐
- 项目管理实践【五】自动编译和发布网站【Using Visual Studio with Source Control System to build and publish website automatically】
在上一篇教程项目管理实践[三]每日构建[Daily Build Using CruiseControl.NET and MSBuild] 中,我们讲解了如何使用CCNET+MSBuild来自动编译项目 ...
- 字符串匹配之boyer-Moore算法
Boyer-Moore算法不仅效率高,而且构思巧妙,容易理解.1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了这种算法. 下面,我根据Moore ...
- 《Windows驱动开发技术详解》之驱动程序调用驱动程序——通过设备指针调用其他驱动程序
本节介绍“手动”构造各个IRP,然后将IRP传递到相应驱动程序的派遣函数里. 获得设备指针 每个内核中的句柄都会和一个内核对象的指针联系起来.ZwCreateFile内核函数可以通过设备名打开设备句柄 ...
- vc里面怎样实现对话框之间传递变量的值
Dialog1的类名是CDialog1, 头文件是dialog1.h.里有成员变量CString str1, str2;Dialog2的类名是CDialog2, 头文件是dialog2.h.里有成员变 ...
- 数据结构——求单向链表的倒数第K个节点
首先,对于链表来说,我们不能像数组一样直接访问,所以我们想到要求倒数第K个节点首先要知道最后一个节点. 然后从最后一个节点往前数K个. 最后得到想要的值. 但是这是不对的,为什么呢?因为题目给出的是单 ...
- ieee80211_rx
ieee80211rx.c(E:\code\linux\net\ieee80211) 所有接收到的帧都送到这个函数中去 int ieee80211_rx(struct ieee80211_device ...
- Python 学习笔记2
今天继续安装配置python. Fear can hold you prisoner. Hope can set you free.
- H5调用本地摄像头
<!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"& ...
- 运维命令rsync
如果你是一位运维工程师,你很可能会面对几十台.几百台甚至上千台服务器,除了批量操作外,环境同步.数据同步也是必不可少的技能. 说到“同步”,不得不提的利器就是rsync,今天就来说说我从这个工具中看到 ...
- Android Studio一直build、一直refreshing、一直buiding gradle project into的终极解决办法
打开我的电脑,打开C:\Users\用户名, 把红圈的文件夹都删了 如果AndroidStudioProjects文件夹里那些project都不重要,也可以跟红圈文件夹删了, 然后再打开android ...