4、总线基础:CAN协议原理、帧格式、仲裁、位时序与错误处理
CAN(Controller Area Network)总线自1986年由Bosch公司为汽车电子系统设计以来,已成为工业控制、医疗设备、轨道交通和机器人领域最可靠的多主串行通信标准之一。与I2C和SPI的短距离板级通信不同,CAN专为长距离(最远1km@50kbps)、强电磁干扰环境下的分布式节点通信而设计。理解CAN协议的核心,不在于记住每个位域的名称,而在于掌握其“非破坏性仲裁”和“分布式错误处理”两大设计哲学。本章将从物理信号特性出发,深入拆解帧结构、仲裁机制、位时序同步策略以及错误处理状态机,为后续驱动开发与设备接入打下坚实的协议基础。
上图展示了CAN协议四大核心模块的关联关系。物理层的差分信号特性决定了显性位(逻辑0)与隐性位(逻辑1)的电气表达,这是仲裁机制的基础;帧格式定义了数据封装规则;位时序则保证了多节点在无统一时钟下的同步采样。下面我们将逐一深入剖析。
4.1 CAN物理层与差分信号原理
CAN总线使用两根双绞线——CANH和CANL——以差分方式传输信号。这种设计使其具有极强的共模噪声抑制能力,这也是CAN能在工业现场和车载环境中可靠工作的根本原因。在显性状态(逻辑0)下,CANH被拉高至约3.5V,CANL被拉低至约1.5V,差分电压约为2V;在隐性状态(逻辑1)下,CANH和CANL均被偏置到约2.5V,差分电压接近0V。
总线终端电阻是物理层设计的关键。标准要求总线两端各接一个120Ω电阻,用于匹配传输线阻抗,防止信号反射。在驱动调试中,若发现总线波形出现振铃或边沿畸变,应首先检查终端电阻是否缺失或阻值漂移。对于低速或短距离(<1m)的测试环境,可以暂时使用单端120Ω,但量产设计必须严格遵循双端匹配。
4.2 CAN帧格式详解:标准帧与扩展帧
CAN 2.0B协议定义了两种帧格式:标准帧(11位标识符)和扩展帧(29位标识符)。两者在仲裁域长度上不同,但数据域最大均为8字节。理解帧格式是编写驱动解析逻辑的前提。
| 帧字段 | 标准帧 (2.0A) | 扩展帧 (2.0B) | 驱动解析要点 |
|---|---|---|---|
| SOF | 1 bit (显性) | 1 bit (显性) | 帧起始同步信号 |
| 仲裁域 | 11 bit ID + RTR | 29 bit ID + SRR + IDE + RTR | ID决定优先级,RTR区分数据/远程帧 |
| 控制域 | IDE + r0 + DLC(4bit) | r1 + r0 + DLC(4bit) | DLC表示数据长度0~8 |
| 数据域 | 0~8 Bytes | 0~8 Bytes | 驱动需校验DLC与实际数据长度一致 |
| CRC域 | 15 bit CRC + 1 bit Delimiter | 15 bit CRC + 1 bit Delimiter | 硬件自动计算,驱动无需干预 |
| ACK域 | 1 bit Slot + 1 bit Delimiter | 1 bit Slot + 1 bit Delimiter | 发送节点释放总线,接收节点回显显性位 |
| EOF | 7 bit 隐性 | 7 bit 隐性 | 帧结束标志 |
在驱动开发中,解析扩展帧时需要特别注意SRR(替代远程请求)位和IDE(标识符扩展)位的处理。SRR位在扩展帧中始终为隐性,用于替代标准帧中的RTR位位置。IDE位为隐性时表示这是扩展帧。许多初学者在解析时容易混淆ID的位序——CAN ID在总线上是MSB先发,但在驱动寄存器中通常以整数形式存储,需要根据控制器手册确认是否需要进行位反转。
4.3 非破坏性仲裁机制
CAN总线的仲裁机制是其最独特的优势。当多个节点同时开始发送时,它们逐位比较ID。由于显性位(0)覆盖隐性位(1),发送显性位的节点在比较中获胜,继续发送;发送隐性位但检测到总线为显性的节点,立即退出发送并转为接收状态。整个过程不破坏任何数据,且没有时间损失。
仲裁过程还涉及RTR位。数据帧的RTR位为显性,远程帧的RTR位为隐性。因此,相同ID下,数据帧优先于远程帧。在驱动实现中,如果使用远程帧请求数据,需要确保接收节点能及时响应,否则发送节点会持续重试,占用总线带宽。
4.4 位时序与同步机制
CAN总线没有独立的时钟线,所有节点依靠位时序同步来保证采样正确。每一位时间(Bit Time)由四个段组成:同步段(SYNC_SEG)、传播段(PROP_SEG)、相位缓冲段1(PSW1)和相位缓冲段2(PSW2)。SYNC_SEG固定为1个时间量子(TQ),用于同步总线上的各节点;传播段用于补偿物理延迟;PSW1和PSW2用于补偿相位误差,采样点位于PSW1和PSW2之间。
// 以STM32 bxCAN为例,位时序配置
// 假设APB1时钟 = 36MHz,目标波特率 = 500kbps
// 所需TQ数 = 36MHz / 500kbps = 72 TQ
// 选择BS1 = 8 TQ, BS2 = 7 TQ, PRESC = 4
// 实际波特率 = 36MHz / (4 * (1 + 8 + 7)) = 500kbps
// 采样点 = (1 + 8) / (1 + 8 + 7) = 56.25%
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; // 同步跳转宽度
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq; // 相位缓冲段1
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq; // 相位缓冲段2
CAN_InitStructure.CAN_Prescaler = 4; // 分频系数
重同步机制是保证通信稳定的关键。当节点检测到总线边沿与本地SYNC_SEG的偏差超过SJW(同步跳转宽度)时,会调整PSW1或PSW2的长度。如果边沿到来晚于预期,则延长PSW1;如果早于预期,则缩短PSW2。SJW的值通常设为1~4 TQ,过大会导致抗干扰能力下降,过小则无法有效同步。
4.5 错误处理与故障状态机
CAN协议定义了完善的错误检测机制,包括位错误、填充错误、CRC错误、格式错误和应答错误。每个节点维护两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。根据计数值,节点处于三种状态之一:主动错误(Error Active)、被动错误(Error Passive)和总线关闭(Bus Off)。
- 主动错误状态(TEC<128, REC<128):节点正常参与通信,检测到错误时发送主动错误标志(6个显性位)。
- 被动错误状态(TEC>127 或 REC>127):节点可以接收和发送,但检测到错误时只能发送被动错误标志(6个隐性位),且发送前需等待8个隐性位(帧间空间)。
- 总线关闭状态(TEC>255):节点完全脱离总线,不参与任何通信。只有在检测到128次连续的11位隐性位后,才能恢复到主动错误状态。
在驱动开发中,错误处理逻辑必须与硬件状态机配合。例如,当控制器进入Bus Off状态时,驱动需要执行恢复流程:停止发送、等待硬件自动恢复或手动复位控制器。许多控制器(如SJA1000)提供错误状态中断,驱动应在中断处理中读取错误码寄存器,区分是位错误还是CRC错误,并采取相应策略。
4.6 案例拆解:CAN总线偶发通信故障排查
背景:某工业设备使用CAN总线连接主控板与三个传感器节点,波特率250kbps,总线长度约3米。设备运行数小时后,偶尔出现传感器数据丢失,重启后恢复正常。
初始现象:使用CAN分析仪抓包,发现错误帧(Error Frame)间歇性出现,且集中在某一传感器节点发送时。错误类型为“位错误”和“填充错误”。
关键数据:示波器测量CANH-CANL差分波形,发现显性位电平仅1.8V(正常应≥2.0V),且下降沿存在明显台阶。总线终端电阻测量为60Ω(正常应为60Ω,即两个120Ω并联),但进一步检查发现其中一个终端电阻焊接不良,阻值漂移至约180Ω。
分析过程:终端电阻漂移导致总线阻抗不匹配,信号反射增强。显性电平下降是因为收发器驱动能力不足——反射波与原始信号叠加,在采样点处产生电平冲突。位错误发生在发送节点发送显性位时,因反射导致总线电压低于阈值,节点误判为隐性位。
操作步骤:① 重新焊接终端电阻,确认阻值稳定在120Ω±1%;② 在总线两端增加共模扼流圈,抑制共模干扰;③ 调整位时序,将采样点从默认的60%调整至75%(通过增加BS1、减少BS2实现);④ 在驱动中增加错误中断处理,记录错误类型和计数器值,便于远程诊断。
结果对比:调整后连续运行72小时,错误帧计数为0,传感器数据丢包率从0.3%降至0%。
复盘经验:CAN总线故障往往不是单一原因,而是多个因素叠加。终端电阻、采样点位置、收发器驱动能力三者必须协同优化。驱动层应提供错误计数读取接口,便于现场快速定位问题节点。