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的操作。

本文相关的代码,可以关注我的公众号“小白白学电子”,留言“资料”获取:

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要连接多个DS18B20温度传感器,需要使用1-Wire总线协议。以下是连接多个DS18B20并测量温度的基本步骤: 1. 初始化1-Wire总线:将总线引脚设置为输出并拉低,然后等待至少480微秒。接下来将总线引脚设置为输入并等待DS18B20响应。 2. 发送ROM命令:向总线发送ROM命令,以便唤醒每个DS18B20并获得其唯一的64位ROM代码。这个代码将用于后续操作。 3. 发送功能命令:向总线发送功能命令,以便读取或写入DS18B20的寄存器。要测量温度,需要发送读取温度的命令。 4. 读取温度值:DS18B20将在总线上发送其温度数据。将读取总线上的数据并将其转换为实际温度值。 5. 重复以上步骤:对于每个DS18B20,重复以上步骤1到4。 以下是一个使用Arduino的示例程序,用于连接多个DS18B20并测量温度: ```C++ #include <OneWire.h> // 定义1-Wire总线引脚 #define ONE_WIRE_BUS 2 // 创建1-Wire总线对象 OneWire oneWire(ONE_WIRE_BUS); void setup() { Serial.begin(9600); } void loop() { byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; // 初始化1-Wire总线 if ( !oneWire.search(addr)) { Serial.println("No more addresses."); Serial.println(); oneWire.reset_search(); delay(250); return; } // 输出DS18B20的唯一ROM代码 Serial.print("ROM ="); for( i = 0; i < 8; i++) { Serial.write(' '); Serial.print(addr[i], HEX); } // 判断DS18B20类型 if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // 发送读取温度的命令 oneWire.reset(); oneWire.select(addr); oneWire.write(0x44, 1); // 等待温度转换完成 present = oneWire.reset(); oneWire.select(addr); oneWire.write(0xBE); // 读取温度值 Serial.print("Temperature = "); byte lowByte = oneWire.read(); byte highByte = oneWire.read(); int16_t temp = (highByte << 8) | lowByte; float celsius = (float)temp / 16.0; Serial.print(celsius); Serial.println(" Celsius"); } ``` 在这个示例程序中,我们使用了OneWire库来实现1-Wire总线协议。在setup()函数中,我们初始化串口通信。在loop()函数中,我们使用oneWire.search()函数来搜索连接到1-Wire总线上的DS18B20设备。对于每个设备,我们输出其唯一的ROM代码,并发送读取温度的命令。最后,我们读取温度值并将其输出到串口。对于每个DS18B20设备,我们重复以上步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值