1. 项目概述:从“一根线”说起
搞嵌入式开发或者物联网设备的朋友,对“单总线协议”这个词应该不陌生。我第一次接触它,是在一个温湿度传感器的项目里,当时看到数据手册上写着“仅需一根数据线即可实现双向通信”,心里直犯嘀咕:一根线怎么又能发又能收?时钟信号又在哪里?这玩意儿靠谱吗?带着这些疑问,我开始了和单总线协议长达数年的“纠缠”。现在回头来看,它绝对是一个被严重低估的通信协议,尤其是在对成本、布线复杂度极其敏感的场合,比如分布式传感器网络、智能家居节点、电池供电设备等,单总线协议往往能成为那个“最优解”。
简单来说,单总线协议是一种主从式、半双工的串行通信协议。它的核心魅力,或者说最大的特点,就是 仅使用一根信号线 来完成数据通信、设备供电(通过寄生供电方式)和时钟同步。这根线既是数据线,也是设备的“生命线”。主设备(通常是我们的MCU)通过控制这根线上电平的时序,来寻址、读取或写入从设备(比如DS18B20温度传感器)。这种极简的设计,直接带来了布线简单、节省IO口、扩展方便(理论上可以挂很多设备)等巨大优势。当然,天下没有免费的午餐,这种简洁性是以更复杂的时序逻辑和软件开销为代价的。接下来,我们就深入拆解这个“一根线”的江湖。
2. 单总线协议的核心原理与通信机制
要玩转单总线,光知道它“一根线”是不够的,必须吃透其底层的工作机制。这就像开车,不能只知道踩油门和刹车,还得懂点发动机原理,出了问题才知道怎么排查。
2.1 物理层与电气特性:共享总线的艺术
单总线的物理连接极其简单:所有从设备(我们称之为“从机”)的数据引脚都并联到主设备(“主机”)的同一个GPIO引脚上,同时通过一个约4.7kΩ的上拉电阻连接到电源(通常是3.3V或5V)。这根总线在空闲时被上拉电阻保持在高电平状态。
这里有几个关键电气特性需要牢记:
- 开漏输出 :无论是主机还是从机,它们的总线驱动电路都是开漏(或开集)结构。这意味着设备只能主动将总线拉低(输出0),而不能主动输出高电平。总线的高电平状态完全依赖于那个外部的上拉电阻。这种设计实现了真正的“线与”功能,避免了多个设备同时驱动时的冲突问题。
- 寄生供电 :这是单总线协议另一个精妙之处。许多单总线器件(如DS18B20)支持寄生供电模式。在此模式下,器件不需要独立的VCC引脚供电。当总线为高电平时,器件内部的一个电容进行充电储能;当总线被拉低进行通信时,器件就依靠这个电容存储的能量工作。这进一步简化了布线,真正实现了“一线通”。但需要注意,在寄生供电下,某些耗电较大的操作(如温度转换)期间,主机必须通过强上拉(例如用一个MOS管将总线直接短接到电源)来提供足够电流。
- 时序即一切 :单总线没有独立的时钟线,时钟信息是通过精心定义的高低电平持续时间来编码的。主机通过产生特定宽度的“复位脉冲”和“时隙”来控制通信流程,从机则通过检测这些脉冲的边沿和宽度来同步并响应。
2.2 通信时序详解:主机主导的“对话”
单总线通信遵循严格的命令序列,每一次完整的交互都始于主机发起的一次复位和存在检测。
复位与存在脉冲 :通信伊始,主机将总线拉低至少480μs(这是一个标准的复位脉冲),然后释放总线(转为接收模式)。由于上拉电阻,总线电平回升。此时,总线上所有的从机在等待15-60μs后,会拉低总线60-240μs,以此向主机宣告“我在这里”。主机在释放总线后的大约60-240μs内采样总线,如果检测到低电平,就表示有从机存在。这个“问-答”过程是后续所有通信的基础。
读写时隙 :复位成功后,主机开始发送ROM命令(用于寻址特定从机)和功能命令(如启动温度转换、读取暂存器等)。无论是命令还是数据,其基本单位都是“时隙”。每个时隙传输1个比特(bit)。
- 写时隙 :主机要向从机写一个比特。写“1”时,主机拉低总线1-15μs,然后释放,剩余时隙时间内总线保持高电平。写“0”时,主机拉低总线至少60μs,最多120μs,然后释放。从机会在主机拉低总线后的15-60μs内对总线进行采样,以此判断是1还是0。
- 读时隙 :主机要从从机读一个比特。主机首先拉低总线1-15μs,然后释放并迅速切换到输入模式。从机在检测到总线被拉低后,如果要输出“1”,则保持总线释放(高电平);如果要输出“0”,则拉低总线。主机在发起读时隙后的15μs内必须完成采样。读“0”的采样窗口相对更宽。
注意 :这些时间参数(如480μs, 60μs, 15μs)是DS18B20的典型值,不同厂商的单总线器件可能略有差异,务必以具体器件的数据手册为准。精确的延时是单总线驱动稳定的关键,在编写代码时,通常需要微秒级的延时函数,并且要考虑中断的影响。
2.3 ROM命令与搜索算法:如何管理多个设备
当总线上挂有多个从机时,如何与其中一个单独对话?这依赖于每个从机出厂时被激光刻录的、全球唯一的64位ROM编码。这个编码包含8位家族代码、48位序列号和8位CRC校验码。
主机通过一系列ROM命令来管理设备:
- 搜索ROM(0xF0) :这是最核心的命令。当主机不知道总线上有哪些设备时,使用此命令。配合一个巧妙的“二进制搜索”算法,可以逐一找出所有从机的完整64位ROM码。这个算法过程稍复杂,其核心思想是利用总线的“线与”特性,在ROM码的每一位上制造冲突,通过检测冲突和主机的人为选择,逐步缩小可能设备的范围,直到唯一确定一个设备。
- 匹配ROM(0x55) :当主机知道目标从机的64位ROM码后,发送此命令,紧接着发送64位ROM码。只有ROM码完全匹配的从机才会响应后续的功能命令,其他从机忽略。这是进行点对点通信的标准方式。
- 跳过ROM(0xCC) :当总线上只有一个从机,或者主机想向所有从机广播命令(例如,同时启动所有DS18B20进行温度转换)时,使用此命令。使用此命令需谨慎,因为如果总线上有多个设备,它们会同时响应后续的数据命令,导致总线冲突,数据读回错误。
搜索算法实操心得 :实现搜索ROM算法是单总线编程的一个小难点。网上有很多示例代码,但直接拷贝常常不工作。关键


5898

被折叠的 条评论
为什么被折叠?



