《I2CSPICAN总线设备接入与驱动实战》

4、总线基础:CAN协议原理、帧格式、仲裁、位时序与错误处理

CAN(Controller Area Network)总线自1986年由Bosch公司为汽车电子系统设计以来,已成为工业控制、医疗设备、轨道交通和机器人领域最可靠的多主串行通信标准之一。与I2C和SPI的短距离板级通信不同,CAN专为长距离(最远1km@50kbps)、强电磁干扰环境下的分布式节点通信而设计。理解CAN协议的核心,不在于记住每个位域的名称,而在于掌握其“非破坏性仲裁”和“分布式错误处理”两大设计哲学。本章将从物理信号特性出发,深入拆解帧结构、仲裁机制、位时序同步策略以及错误处理状态机,为后续驱动开发与设备接入打下坚实的协议基础。

CAN 2.0B 协议核心机制总览 物理层特性 差分信号 CANH/CANL 显性0 / 隐性1 帧格式 标准帧(11bit ID) 扩展帧(29bit ID) 非破坏性仲裁 ID优先级逐位比较 显性位覆盖隐性位 位时序 SYNC/PSW1/PSW2 重同步 标准数据帧结构(44~108 bits) SOF 仲裁域 ID+RTR 控制域 IDE/DLC 数据域 0~8 Bytes CRC域 15bit+Del ACK域 Slot+Del EOF 7bit 错误处理状态机 主动错误 被动错误 离线 TEC>127 TEC>255 128次11位隐性位监测后恢复 位时序与采样点 SYNC PSW1 PSW2 采样点 典型配置: 16TQ → 采样点 = (1+8)/16 = 56.25% 重同步: PSW1可延长, PSW2可缩短 SJW = 4TQ (最大)

上图展示了CAN协议四大核心模块的关联关系。物理层的差分信号特性决定了显性位(逻辑0)与隐性位(逻辑1)的电气表达,这是仲裁机制的基础;帧格式定义了数据封装规则;位时序则保证了多节点在无统一时钟下的同步采样。下面我们将逐一深入剖析。

4.1 CAN物理层与差分信号原理

CAN总线使用两根双绞线——CANH和CANL——以差分方式传输信号。这种设计使其具有极强的共模噪声抑制能力,这也是CAN能在工业现场和车载环境中可靠工作的根本原因。在显性状态(逻辑0)下,CANH被拉高至约3.5V,CANL被拉低至约1.5V,差分电压约为2V;在隐性状态(逻辑1)下,CANH和CANL均被偏置到约2.5V,差分电压接近0V。

关键理解:显性位具有“覆盖”能力。当多个节点同时发送时,只要有一个节点输出显性位,总线上就呈现显性状态。这一电气特性直接实现了“线与”逻辑,是CAN非破坏性仲裁的物理基础。驱动开发中,必须确保收发器(如TJA1050、SN65HVD230)的共模输入范围覆盖-12V~+12V,否则在恶劣环境下可能损坏收发器。

总线终端电阻是物理层设计的关键。标准要求总线两端各接一个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),发送显性位的节点在比较中获胜,继续发送;发送隐性位但检测到总线为显性的节点,立即退出发送并转为接收状态。整个过程不破坏任何数据,且没有时间损失。

实战经验:在驱动设计中,ID分配直接决定系统实时性。例如,在电机控制系统中,速度环控制帧(ID=0x001)应比温度上报帧(ID=0x100)具有更高优先级(数值越小优先级越高)。如果ID分配不合理,高频率的调试信息可能阻塞关键控制帧的发送。建议在系统设计阶段就规划好ID分段:控制帧(0x000~0x07F)、状态帧(0x080~0x1FF)、诊断帧(0x200~0x7FF)。

仲裁过程还涉及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,过大会导致抗干扰能力下降,过小则无法有效同步。

风险提示:采样点位置对通信质量影响极大。推荐将采样点设置在75%~85%位时间位置,以容忍信号上升沿的延迟和总线寄生电容的影响。如果采样点过早(<50%),在长线缆或高波特率下极易出现采样错误。使用示波器观察CAN_H和CAN_L的差分波形,测量实际位时间,是验证时序配置是否正确的有效手段。

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总线故障往往不是单一原因,而是多个因素叠加。终端电阻、采样点位置、收发器驱动能力三者必须协同优化。驱动层应提供错误计数读取接口,便于现场快速定位问题节点。