1-wire总线上挂载多个18b20温度传感器的用法
DS18B20是常用的数字温度传感器,具有体积小,精度高,占用硬件资源少等优点。
它的突出优点在于采用单总线(1-wire)的接口方式,与微处理器连接时仅需要一根信号线即可实现双向通讯。甚至供电线也可以不用,直接通过寄生方式从信号线上取电,可只连接信号线(DQ)和GND即可使用。
DS18B20内部具有64位固化在ROM中的序列号,可以用来识别不同器件;所以,在单总线上,可以挂载多个DS18B20,以实现最少的连接挂载多个器件。
本文主要介绍在单总线上挂载多个DS18B20温度传感器的使用方法。
首先了解一下单总线的硬件结构,看其datasheet里的结构图:
这个图里说明,DS18B20在输出时,是靠拉低DQ通信线实现低电平输出,靠释放DQ通信线(被上拉电阻拉高)来实现高电平输出。
也就是说它可以实现“线与”。多个DS18B20同时输出时,只要有一个低电平,则DQ通信线就会被拉低,只有低电平能被识别,只有都为高电平是,总线上才是高电平。单总线上识别不同的DS18B20就是靠“线与”来解决通信冲突的。
当单总线上挂载多个DS18B20时,MCU必须知道每个DS18B20内部固化的64bit序列号,才能分别和它们通信。所以MCU如何获取DS18B20内部的序列号,就是解决问题的关键。
DALLAS官方给出的文档中,介绍了通过单总线获取DS18B20内部序列号ID的方法,访问每个bit时,分为三步:
先读取第一位;
再读取第一位的补码;
通过读取的数据和补码,和下表对应的结论,来判断总线上的器件状态:
然后写一位数据,告诉从器件,主机MCU选择了哪些器件继续通信;如果从机当前ROM码全为0,则写0;如果从机当前ROM码全为1,则写;如果从机当前ROM码有0也有1,则MCU可以先写0,选择为0的器件继续通信;等本次后续的bit位都搜索完后,再回到此处,选择为1的器件,到另一个分支搜索。
MCU就是通过不断循环、回溯,完成所有器件的搜索,获取所有器件的序列号。
描述起来有点难懂,可以看具体的例子:
假如总线上挂载了三个DS18B20,我们命名为a、b、c器件,为简化处理,假设器件ID只有两位,分别是:01、00、11;MCU从低位开始读取。
a)第一轮通信
主机MCU先读取第1位,a的最低位为1、b的最低位为0、c的最低位为1,由于最低位有0,所以总线数据会被识别为0;
再读取第1位的补码,a的最低位补码为0、b的最低位补码为1、c的最低位补码为0,则总线数据也会被识别为0;
主机MCU识别到两次都为0,则知道总线上有器件为0、也有器件为1;则主机MCU需要选择一条路径继续访问;如果我们的算法选择优先访问0的路径;则向总线上写入一个0位;三个从器件收到发送来的0后,只有b器件的对应位符合,则下一次通信时,a、c器件都不会再响应;
b)第二轮通信
主机MCU开始读取第2位,由于只有b器件响应,则读到0;
再读取第2位的补码,由于只有b器件响应,可以读到1;
主机MCU两次读取到0、1,则可以判定总线上的器件该位为0;
又因为,上一轮选择的是0路径,加上本次识别到的0,则可以断定,总线上有一个器件的ID是00;识别完ID的总长度(2位)后,本次搜索结束。
c)回溯后再次通信
与第一轮通信类似,最后写入的位改为1;则只有a、c器件的对应位符合,后续只有a、c器件会继续通信,b器件不再响应;
主机MCU开始读取第二位,读取到0;
读取补码,读到0;
则主机可以断定,第二位有0、也有1;再加上上一轮通信中选择的1路径,则可以断定,总线上有两个器件:10和11。
至此,所有ID搜索完毕,搜索的示意见下图:
实际的DS18B20的ID有64bit,搜索的原理是一样的,以此可以获取总线上所有器件的ID,之后就可以通过ID来访问特定器件了。
一种实现搜索ID的方法如下代码所示:
该算法来源于网络。另外,DALLAS官方也给出了效率更高的一种实现方法,代码比较长,这里就不贴了,感兴趣的可以在文末留言自行获取。
如果总线上只挂载了一个器件,通常我们可以不用理会序列号ID,直接跳过ID号识别这个步骤,如下示例来访问:
Ds18Write(0xcc); //跳过ID号指令
Ds18Write(0xbe); //读取指令
当获取了ID号之后,我们就可以通过指定ID号来访问特定的器件,如下示例访问:
Ds18Write8Btye(DS18B20_ID); //写入8Btye(即64bit)的ID号
Ds18Write(0xbe); //读取指令
这样,我们就可以分别获取每个器件的数据了,实现了单总线上挂载多个DS18B20的操作。
本文相关的代码,可以关注我的公众号“小白白学电子”,留言“资料”获取: