ONEWIRE基础
一、onewire 的一些基础概念
1.1 onewire 是什么
onewire 就是单总线技术,允许多个设备通过一条数据线进行通信。
与传统的多线通信接口(如I2C、SPI等)相比,onewire只需要一条数据线,大大简化了电路设计和布线复杂度。
onewire 总线技术,是 Dallas 半导体公司在 1989 年提出的技术。
2001 年,Maxim Integrated 并购了 Dalls。
2020年,ADI 并购了 Maxim。
所以,onewire 技术当前是有 ADI 在维护。
onewire 没有一个单独的技术文档,当前是在 ADI 的wiki 网站上,有多个文档分散的介绍 onewire 技术,显得颇为凌乱。
但是由于 onewire 实在是太简单实用,所以至今还是有非常多的设备支持 onewire。
1.2 onewire 的主从设备关系
onewire 总线只能有一个主设备,可以有多个从设备,也可以只有一个从设备。
每一个从设备,都有一个64位bit 的地址,也就是8字节的地址,这64位是先传输MSB(高位比特)的。
第1个字节是家族代码,用来识别是哪种设备。
第2到7个字节是设备id,也就说每种设备可以有2的48次方个id,绝对可以做到全球唯一id;
第8个是前7个字节的CRC8校验码。
这8 字节,64位,存储在onewire 设备的不可擦除的存储空间里面, 用来让主设备来寻址通信,也成为onewire设备的 ROM id。
1.3 ROM id 的家族码
onewire 的第一个字节所标识的种类,详细的家族代码在这里可以查到:
这些家族代码,全都是 maxim 的产品。
即使这样, onewire 还是非常流行,产生了很多兼容 onewire 协议的产品。
为了读者方便,我把截止到2025年4月11日有效的家族代码抄录如下:
(1)0x02 - DS1991 maxim 的一款iButton,多密钥安全存储器,集成了NVRAM、RTC、计数器。
(2)0x04 - 四款设备共用 0x04家族码:
DS2404,Maxim的一款 EconoRAM Time Chip,集成了NVRAM、RTC、计数器。
DS2404S,DS2404 的SOIC-16封装;
DS1994, maxim 的另一款 iButton;
DS1427, maxim 的又一款 iButton;
(3)0x05 - DS2405,Maxim 的一款可寻址开关,集成了 64 位 ROM ID 和一个可控的开漏 N 通道 MOSFET,用于远程控制和状态检测。
(4)0x06 - DS1993, 4kbit Memory iButton
(5)0x08 - DS1992, 1kbit Memory iButton
(6)0x09 - DS2502,DS2703, DS2704 存储器
(7)0x0A - DS1995, 16kbit Memory iButton
(8)0x0B - DS2505, 存储器
(9)0x0C - DS1996, 64kbit Memory iButton
(10)0x0F - DS2505, 存储器
(11)0x10- DS18S20,温度传感器
(12)0x12 - DS2406, switch
(13)0x14 - DS2430A, 存储器
(14)0x18- DS1963S, DS1962, iButton
(15)0x1C - DS1963L, Monetary iButton
(16)0x1D - DS2423, Counter
(17)0x1E - DS2437, Battery monitor
(18)0x1F - DS2409,Microhub
(19)0x20 - DS2450, Voltage monitor
(20)0x21 - DS1921, Thermocron
(21)0x23 - DS2433, DS1973, Momory
(22)0x24 - DS2415, Clock
(23)0x26 - DS2438, Battery monitor
(24)0x27 - DS2417,Clock + interrupt
(25)0x28 - DS18B20, Temperature, sensor
(26)0x29 - DS2408, Switch,
(27)0x2C - DS2890, Varible Resitor
(28)0x2E - DS2770, Battery
(29)0x30 - DS2760, Battery
(30)0x31 - DS2720, Battery
(31)0x32 - DS2780, Battery
(32)0x35 - DS2755, Battery
(33)0x36 - DS2740, Coulomb counter
(34)0x3A - DS2413, Switch
(35)0x3D - DS2781, Battery
(36)0x42 - DS28EA00, Temperature, sensor
(37)0x43 - DS28EC20,Memory
(38)0x51 - DS2751, Battery Monitor
(39)0xEE - UVI,Ultra Violet Index
(40)0xEF - Moisture Hub
(41)0xFC, BAE0910, Pascal Baerten公司的一款多功能 1-Wire 从设备,主要用于 1-Wire 网络中的自动化和控制应用。
(42)0xFF - Swart LCD
其他公司如果做了同样支持onewire 协议的同样功能的设备,是申请不到 ROM id 的,因此只能用跟以上列表的相同的 ROM 的家族码。
1.4 onewire 的典型设备
onewire 最流行的设备就是温度传感器,maxim 的DS18B20。
国产的很多兼容 DS18B20 的传感器, 性能非常接近,并且总线完全兼容 DS18B20,romid 的家族码也跟 DS18B20相同,都是 0x28.
1.5 理解onewire 和 GPIO的关系
onewire 本质是 GPIO 的一个应用。
主设备通过在 GPIO 的持续输出,让从设备能够读到不断变化的值,获取到主设备发给从设备的信息;
从设备也通过在 GPIO 的持续输出,让主设备获取到从设备发过来的信息。
在主设备发送信息的时候,从设备是不能改变该GPIO的电平的,只能读取电平;
在从设备发送信息的时候,主设备是不能改变该GPIO的电平的,只能是读取电平。
这种能双向通信,但是不能在同一时间双向通信的方式,称为半双工通信。
maxim 定义了一种基于一根GPIO 的严格时序的半双工的高效的通信方式,称为 onewire 总线。
为了实现这种稳定的通信,主设备和从设备的这跟GPIO,都要设置为开漏输出模式。
1.6 开漏输出和线与逻辑
推挽输出有三种工作状态: 高电平输出,低电平输出,高阻态。
而开漏输出只有两种工作状态: 低电平输出,高阻态。
开漏输出模式下,GPIO 是不可能主动输出高电平的,要想获得高电平,只能依赖外部的上拉电阻。
所以,在开漏输出模式下, 如果主设备和从设备都不控制这个总线的情况下, 通过上拉电阻,会把总线通过上拉电阻置位高电平。
开漏输出模式有什么好处呢?
先强调这两点:
(1)当总线上的所有设备什么都不做的时候,所有设备对总线的控制都是高阻态(称为释放总线),由于上拉电阻的存在,总线就是高电平。
(2)当总线上的任一设备要做控制总线的动作,只要一个动作能做:拉低电平,这样总线就变成了低电平。
任意设备拉低总线能获得低电平, 但是要所有总线释放设备,才能获得高电平。
把低电平记为逻辑0, 高电平记为逻辑1,
所有设备都一起释放,才能获得逻辑1,任意设备做动作,就能获得逻辑0, 这样的逻辑,叫做线与逻辑。
onewire 总线,就是基于线与逻辑的总线方式。
开漏输出模式的好处,是能够实现线与逻辑,这是 onewire 总线,也是其他很多总线通信的前提条件。
二、onewire 总线的详细定义
2.1 onewire 总线的主设备和从设备
一条 onewire 总线,只能有一个主设备,可以有多个从设备,从设备的数量没有限制。
主设备在每次通信之前,都会发起复位信令,通过复位应答,确保从设备是ready状态。
在确定从设备是ready状态之后, 主设备会发起后续的命令,进行业务操作,从设备根据收到的命令进行响应的回复。
2.2 总线的通信状态
总线的通信状态有三个: 空闲,复位,数据交换。
通过低电平的持续时间, 来区分不同的通信状态。
2.2.1 空闲状态
在空闲的时候,onewire 总线是持续保持高电平。
2.2.2 复位状态
如果低电平持续时间超过了 480us, 是复位的通信状态。
通过发起复位,主设备告诉从设备,我们要开始通信了,你如果想要跟我通信的话,就给我个复位响应吧。
主设备通过收到复位响应,会知道有设备想跟他通信,主设备就会发起下一步的数据交换命令。
如果主设备收不到复位响应,说明总线上没有合适的设备,接下来主设备就啥也不做了。
2.2.3 数据交换状态
如果低电平持续时间大于1us但是小于120us,就是数据的交换状态,在这个状态下,有4种可能性:
(1)主设备发送1,所有从设备都可以接收1;
(2)主设备发送0,所有从设备都可以接收0;
(3)主设备接收1,同时约定好的从设备可以发送1,
(4)主设备接收0,同时约定好的从设备可以发送0.
在数据交换状态下, 从设备无论是接收数据一个bit还是发送一个bit数据,都要先观察到主设备先发起了低电平之后,才能进行接收数据和发送数据。
那么,你可能会有疑问: 从设备怎么判断, 当前是应该数据还是发送数据呢?
答案是: 仅仅从主设备发起的电平的时序变化,是无法判断当前是应该发送还是接收的,从设备必须是根据主设备发过来的数据,
解析出来具体的报文命令是什么,然后才能判断当前的数据交换,是应该发送还是应该接收。
这一点,非常重要,是从设备设计自己行为的基础条件。
2.3 复位的详细定义
2.3.1 复位的时序图
主设备拉低总线超过480us,就视为发起了复位。
从设备在检测到复位信号后,等待主设备释放总线,并且在检测到主设备释放总线(电平从低到高)后的15-60us的区间,
拉低电平做响应,拉低电平的持续时间在60-240us之间都是有效的响应。
主机会在释放总线后的15us之内,持续检测总线是否有持续的低电平,来证实是否有从设备给响应。
下图是总线复位的时序示意图。
图1 onewire 复位时序图
总线通过拉低480us发起复位信号,最长的主机拉低总线的时间可以持续多长?
答案是持续多长都可以,没有规定,从机会一直等待主机释放总线,从低电平到高电平,然后再做响应。
但是过长的拉低时间,会降低总线通信效率,所以一般也不会把复位的拉低时间做的太长,不小于480us就可以了。
如果主机检测到了复位响应的有效低电平, 只能是证明有从设备存在,但是无法知晓有几个从设备存在。
主机会通过后续的 rom id 的上层命令,去确定和主机通信的具体设备是哪个。
2.3.2 几个关键参数
由于是onewire 总线的时序有灵活性,所以在具体实现的适合,主机需要确定关键参数,用来指导自己的具体时序行为。
2.3.2.1 tRSTL
tRSTH - Reset Low Time
主机发起复位的拉低电平的总时间,最低是 480us,最高不限。
建议这个值定义为 500.
2.3.2.2 tRSTH
tRSTH - Reset High Time
它表示主设备在发送复位信号后释放总线并保持高电平的时间。
这段时间是从设备拉低电平,让主设备对从设备做存在检测(Presence Detect)的时间段。
tRSTH 最小值也是 480us。
建议这个值定义为 500。
2.3.2.3 tPDHIGH
tPDHIGH(Presence Detect High Time),是指从设备在发送存在低电平脉冲(Presence Pulse)前,仍然保持总线高电平的时间。
该参数是复位周期时序的关键部分,影响主设备检测从设备存在的可靠性。
时序位置:主设备释放总线(结束复位低电平信号)后,从设备检测到高电平并开始计时,计时到 tPDHIGH 之后,开始拉低总线,发送存在脉冲。
tPDHIGH 的取值建议为 15us。
2.3.2.4 tPDLOW
tPDLOW 是指 Presence Detect Low Time,即从设备在响应主设备复位信号时,将总线拉低的时间。
该参数的作用:从设备通过拉低总线来发送存在脉冲,主设备通过检测该低电平确认从设备是否在线。
时序位置:主设备拉低总线发送复位信号后,从设备检测到复位信号结束,并等待 tPDHIGH 这么长时间后,开始拉低总线,并持续 tPDLOW 这么长时间。
tPDHIGH 的取值建议为 240us。
2.4 主设备发送数据的详细定义
2.4.1 时序描述
复位的流程完成后,主设备就会发送第一个命令给总线的所有从设备。
主机发生所有数据,都是一个bit 一个bit 的发送,发完一个比特,再发送下一个bit,直到把一个命令的所有bit发送完成之后,才会停止发送,然后进入读数据的状态。
而从机收到了完整的命令之后,会进入发送数据的状态。
主机无论是发生0还是1, 都是先拉低总线,持续时间至少1us。
从设备检测到这个拉低信号,就开始准备检测是主机发生的是0还是1,
从机检测信号的时间,是从检测到低电平开始,到15us之后。
如果从机检测到低电平,说明主机发送的是0,
如果从机检测到的是高电平,说明主机发送的是1.
对主机来说,如果想要发送1, 就在拉低电平一段时间之后,就释放总线,让总线恢复高电平。
持续拉低电平的时间,在1-15us之间都可以,这样可以确保从机检测到高电平。
如果想要发送0, 就要把拉低电平的持续时间,不小于60us,确保从机能检测到低电平。
从主机拉低电平启动数据发送,到整个时隙结束,不能超过120us。
也就是说,在120us之内,主机必须释放总线,进入空闲状态,为进入下一个数据交换时隙做准备。
下图是主机发送一个bit 的时序图。
图2 主机发送数据示意图
2.4.2 关键参数
2.4.2.1 tSLOT
tSLOT 是指 时间片持续时间(Time Slot Duration)。它定义了主设备和从设备之间,在发送数据和接收一个bit 的一个通信周期内所需的总时间,
包括低电平持续时间和释放总线的恢复时间。
tSLOT 的取值范围是 60us到120us之间。
建议取值 65us。
tSLOT 表示每个位传输的完整时长,包括主设备拉低总线、从设备响应以及总线恢复到高电平的时间。
时序位置: 从主设备发起一个写或读操作开始,到该操作结束并进入下一个时间片为止。
2.4.2.2 tStart
tStart 指的是 时间片开始时间(Start Time),即主设备发起一个时间片(时隙)时,数据线从高电平被拉低的时间点。
这是 1-Wire 通信时序中的一个重要参数,用于定义主设备如何开始发送数据位。
从设备通过检测总线的下降沿来识别时间片的开始,并同步其内部计时器。
tSart 的值最小可以是0,最大无限制。
建议取值为 1us。
2.4.2.3 tLOW1
tLOW1 是指 写逻辑 1 时的低电平持续时间(Write-1 Low Time)。
它是主设备在发送逻辑 1 时,将总线拉低的时间段,用于区分逻辑 1 和逻辑 0。
主设备发送逻辑 1时,主设备将总线拉低很短的时间就是tLOW1,然后释放总线,让其恢复到高电平。
tLOW1 的最小取值是 1us,最大取值是 15us。
建议取值 15us。
2.4.2.4 tREC
tREC 是指 恢复时间(Recovery Time)。
它表示主设备或从设备完成一次操作后,总线需要保持高电平的时间,以确保所有设备准备好进入下一次通信周期。
作用:在每个通信时隙(如读写操作)结束后,总线需要一定的恢复时间,以充电寄生电容并确保从设备能够正确响应下一次命令。
tREC 是总线从低电平恢复到高电平并稳定的时间。
时序位置: 每个通信周期(如写 0、写 1 或读操作)结束后,进入恢复阶段,数据线通过上拉电阻恢复到高电平。
tREC 的最小值为 5us,最大值无限制。
建议取值为5us。
2.5 主设备接收数据的详细定义
2.5.1 时序描述
从机收到了多个bit,直到接收到了完整的命令之后,会进入发生数据的状态,此时主机也进入到接收数据的状态。
此时,主机先拉低总线,持续时间至少1us。
从设备检测到这个拉低信号,就开始准备发送数据。
从机发送信号的时间,是从检测到低电平开始,到15us之后。
如果从机想发送低电平,就在检测到主机释放总线后的15us之内,拉低总线,并且拉低总线的持续时间不低于60us,确保主机能检测到低电平,认为从机发送了0.
如果从机想要发生高电平,就什么都不做,保持总线为高电平,主机如果检测到是高电平,就认为从机发送了1.
从主机拉低电平启动数据读取,到整个时隙结束,不能超过120us。
也就是说,在120us之内,从机必须释放总线,进入空闲状态,为进入下一个数据交换时隙做准备。
下图是主机读取一个bit 的时序图。
图3 主机读取数据示意图
2.5.2 关键参数
2.5.2.1 tSLOT
同 2.4.2.1
2.5.2.2 tStart
同 2.4.2.2
2.5.2.3 tRDV
tRDV 是指 读数据有效时间(Read Data Valid Time)。
它定义了主设备在读时隙中采样总线状态的时间点,用于确定从设备发送的逻辑位值。
作用:主设备在发起读时隙后,必须在 tRDV 时间点采样总线状态,以读取从设备发送的逻辑位。
时序位置:从设备发起读时隙时,将总线拉低至少 tStart us(1us),然后释放总线后,再等待 tRDV 时间后,主设备采样总线状态。
tRDV 的最小取值为 15us,最大值无限制。
建议取值15us。
2.5.2.4 tREC
同 2.4.2.4
三、onewire 总线的供电方式
onewire 总线设备的主设备,需要单独的电源供电;
从设备,可以有两种供电方式: 寄生供电和独立供电。
寄生供电,是指通过总线给从设备的电容充电, 用电容的电量,为从设备提供电源;
独立供电,是指通过独立的电源引脚,给从设备的 VCC 管脚供电。
DS18B20 提供了单独的 VCC 管脚,用独立供电方式,通信会更加稳定。
780EPM 的一部分 GPIO 管脚,电压设置为 3v 后,是可以为 DS18B20 的 VCC 引脚供电的。
四、onewire 总线的典型电路
典型的onewire 电路如下图所示,主控CPU 和从设备DS18B20通过单总线相连,并且把总线接一个上拉电阻到高电平。
DS18B20 的 VCC 管脚外接供电,这种供电方式比用总线寄生供电更加稳定。
在实际应用中,DS18B20 的 VCC 是接了 780EPM模组的一个有电流驱动能力的GPIO。
图4 onewire 典型电路
五、onewire 总线通信的典型命令
Onewire 总线的典型命令主要有两类: ROM ID 的操作命令和从设备数据操作的命令。
5.1 ROM ID 操作命令
ROM功能命令用于设备识别和选择,主要操作设备的唯一64位ROM ID。常见的ROM功能命令包括:
暂时无法在飞书文档外展示此内容
5.1.1 Read ROM 0x33
Read ROM 命令, 是发送命令给所有的从设备,让所有从设备把自己的8字节ROM ID发给主设备。
这个命令适合 onewire 总线只有一个从设备的情况,只需要一次命令交互,就可以获得从设备的ROM ID。
存在多个从设备有使用这个命令的话,会使得多个从设备同时发送自己的ROM ID, 会造成总线的数据混乱。
5.1.2 Match ROM 0x55
知晓了传感器的 ROM ID 后,用 match ROM 命令 0x55搭配其他命令,按照先后次序一起发送,可以要求单个传感器做各种业务动作。
5.1.3 Search ROM 0xF0
如果总线存在多个从设备,反复发送 search ROM 命令,并等待从设备的回复,可以获取所有从设备的ROM ID,并记录到主机的存储器。
获取之后,可以用 match ROM 命令,要求从设备做各种业务。
具体搜索的算法参见 5.4 小节。
5.1.4 SKip ROM 0xCC
当总线只有一个从设备的适合,用0xCC命令加上业务命令,可以要求总线的设备做各种业务动作,省却了读取和匹配ROM ID 的麻烦。
5.2 设备数据操作命令
设备操作的命令用于与设备的内部寄存器或存储器交互。
这些命令因具体设备而异,例如温度传感器、EEPROM等。
以下是DS18B20 的常见操作命令:
暂时无法在飞书文档外展示此内容
5.3 典型的通信流程
5.3.1 总线只有一个传感器的典型流程
对于只有一个DS18B20 从设备的onewire总线系统来说,典型的通信流程是这样的:
(1)主机发送复位信号(Reset),确认有从设备传感器存在。
(2)主机通过ROM读取命令 0x33, 让从设备回复自己的ROM ID;
(3)主机读取从设备发生的 ROM ID,校验是否合法;
(4)主机发送 Skip ROM命令给从设备,指明后续通信只针对该设备;
(5)主机发送 convert 命令 0x44,启动DS18B20的温度转换,更新暂存器的数据;
(6)主机发送读取暂存器内容命令 0xBE,读取DS18B20的温度。
5.3.2 总线有多个传感器的典型流程
对于有多个DS18B20 从设备的onewire总线系统来说,典型的通信流程是这样的:
(1)主机发送复位信号(Reset)。
(2)主机通过多次search ROM命令 0xF0, 获取到所有从设备的 ROM id,记录到主机的存储器中;
(3)主机选择其中一个传感器,发送 Match ROM命令0x55+0x44命令给从设备,要求采集传感器;
(4)主机选择另外一个传感器,发送 Match ROM命令0x55+0x44命令给从设备,要求采集传感器;依次类推,直到给所有传感器发送完命令为止;
(5)主机依次发送Match ROM命令0x55+0xBE命令给从设备,要求读取传感器数据,并等待传感器发送温度数据并采集,重复多次,直到采集所有传感器的温度数据;
5.4 搜索ROM ID 的算法
在 onewire 总线中,主设备通过 搜索算法(Search Algorithm) 发现b并记录所有从设备的 ROM ID。
该算法基于二叉树遍历,通过逐位探测从设备的 ROM ID 比特位,逐步确定每个设备的唯一标识。以下是具体步骤和原理:
5.4.1 算法核心思想
(1)二叉树遍历:将 ROM ID 的每一位视为二叉树的节点,通过逐位探测分支路径(0 或 1),最终找到所有叶子节点(即所有从设备的 ROM ID)。
(2)分歧处理:当多个从设备的某一位存在不同值(即存在 0 和 1 的分歧),主设备记录分歧位置,并在后续搜索中遍历另一分支。
5.4.2 搜索流程
步骤 1:初始化
(1)主设备发送 复位脉冲(Reset Pulse),所有从设备响应存在脉冲(Presence Pulse)。
(2)主设备发送 搜索命令(0xF0):
步骤 2:逐位探测
主设备对 ROM ID 的 每一位(从最低位到最高位)执行以下操作:
(1)读取当前位(Bit):
(2)所有从设备同时发送当前 ROM ID 位的值。
(3)由于线与逻辑的作用,主设备读取的值为所有从设备的逻辑 AND(若任一设备发送 0,则主设备读到 0,所有设备都发送1,主设备才能读到1)。
(4)读取补码位(Complement Bit):
所有从设备发送当前 ROM ID 位的补码(0 变为 1,1 变为 0)。
主设备再次读取逻辑 AND。
(5)分析结果:
根据两次读取结果,判断当前位的可能值(见下表):
暂时无法在飞书文档外展示此内容
步骤 3:处理分歧
(1)若存在分歧:
主设备选择一条路径(优先选择 0),并记录分歧位置(Last Discrepancy)。
未匹配路径的从设备进入等待状态,直到下次复位。
(2)若无分歧:
主设备直接写入当前位的值。
步骤 4:循环探测
(1)重复步骤 2~3,直到处理完 64 位 ROM ID。
(2)主设备记录完整的 ROM ID,并开始下一次搜索,从最后一个分歧位置切换路径。
(3)关键状态变量:
-
Last Discrepancy:记录最近一次分歧的位置,用于指导下一次搜索路径。
-
Last Family Discrepancy:记录家族码(Family Code)的分歧位置,用于快速筛选特定类型设备。
-
Last Device Flag:标记是否已找到所有设备。
5.4.3 示例
假设总线上有两个设备,其 ROM ID 分别为:
-
Device 1:1010
-
Device 2:1001
(1)探测第 1 位:
-
所有设备发送第 1 位:1 AND 1 → 1。
-
补码位:0 AND 0 → 0。
-
结果:无分歧,主设备写入 1。
(2)探测第 2 位:
-
设备发送 0 AND 0 → 0。
-
补码位:1 AND 1 → 1。
-
结果:无分歧,主设备写入 0。
(3)探测第 3 位:
-
设备发送 1 AND 0 → 0(存在分歧)。
-
主设备记录分歧,选择 0 路径,找到 Device 2(ROM ID 1001)。
(4)下次搜索:
- 主设备从分歧位置切换路径(选择 1),找到 Device 1(ROM ID 1010)。
5.4.4 算法优化
(1)家族过滤:通过设置目标家族码,跳过无关设备。
(2)CRC 校验:验证 ROM ID 的完整性,避免错误。
(3)高速模式:使用 Overdrive 命令加速搜索(速率提升至 142kbps)。
5.4.5 总结
onewire 搜索算法通过逐位探测和分歧处理,高效遍历所有可能的 ROM ID,适用于多从设备场景。
其核心在于动态记录分歧位置并切换路径,最终枚举总线上所有设备的唯一标识。
六,通过onewire总线实现读取 DS18B20 的代码示例
demo 代码的实现流程