2. CAN报文结构详解:标准帧与扩展帧、数据帧、远程帧、错误帧、过载帧、帧间隔

CAN协议定义了五种基本帧类型和一种帧间隔结构,理解这些帧的格式与用途是进行报文过滤与ID分配优化的前提。本章将逐一拆解每种帧的位域结构、仲裁机制及应用场景。

2.1 标准帧与扩展帧:ID长度的差异

CAN 2.0A(标准帧)使用11位标识符(ID),CAN 2.0B(扩展帧)使用29位标识符。两者在仲裁场和帧结构上存在关键区别。

特性标准帧(Base Frame)扩展帧(Extended Frame)
ID长度11位29位
IDE位显性(0)隐性(1)
SRR位无替代远程请求位(隐性)
仲裁场长度12位(ID + RTR)32位(ID + SRR + IDE + RTR)
数据场最大长度8字节8字节
总线利用率较高(帧头短)较低(帧头多21位)
典型应用动力总成、车身控制ADAS、信息娱乐、多ECU系统
关键点:标准帧与扩展帧可以共存于同一总线。当标准帧与扩展帧ID高位相同时,标准帧因IDE位显性而获得更高优先级。在报文过滤配置中,必须明确指定帧类型(标准/扩展),否则硬件过滤器可能无法正确匹配。

2.2 数据帧:承载应用信息的核心帧

数据帧是CAN总线最常用的帧类型,用于从发送节点向一个或多个接收节点传输数据。其完整结构包含七个场:帧起始、仲裁场、控制场、数据场、CRC场、ACK场、帧结束。

数据帧位域结构(标准帧示例) SOF 11位ID + RTR IDE + DLC 数据场(0~8字节) Data[0] ~ Data[7] CRC 15位+定界符 ACK +定界符 EOF 1位 12位 6位 0~64位 16位 2位 7位 各场说明: • SOF(帧起始):1位显性位,同步所有节点。 • 仲裁场:ID决定优先级,RTR区分数据帧(显性)与远程帧(隐性)。 • 控制场:IDE标识标准/扩展帧,DLC指示数据字节数(0~8)。 • CRC场:15位CRC校验 + 1位隐性定界符,保障数据完整性。 • ACK场:接收节点发送显性位确认,发送节点检测。 • EOF(帧结束):7位隐性位,标志帧结束。

2.3 远程帧:请求数据而不发送数据

远程帧用于一个节点主动请求另一个节点发送数据。其结构与数据帧几乎相同,但RTR位为隐性(1),且数据场为空(DLC指示期望接收的数据长度)。

远程帧 vs 数据帧对比:
  • RTR位:数据帧为显性(0),远程帧为隐性(1)。
  • 数据场:数据帧包含0~8字节数据;远程帧无数据场。
  • 优先级:相同ID下,数据帧优先级高于远程帧(RTR显性优先)。
  • 典型场景:传感器节点收到远程帧后,采集数据并以数据帧回复。

2.4 错误帧:总线错误通知机制

当任何节点检测到总线错误时,立即发送错误帧,通知所有节点丢弃当前报文。错误帧由错误标志和错误定界符组成。

错误类型触发条件错误标志长度
位错误发送节点监控到总线电平与发送电平不一致6位显性位
填充错误检测到连续6个相同电平位(违反位填充规则)6位显性位
CRC错误接收节点计算的CRC与发送CRC不匹配6位显性位
形式错误固定格式位(如EOF、定界符)出现错误电平6位显性位
应答错误发送节点在ACK槽未检测到显性位6位显性位
工程注意:错误帧的发送会导致总线进入错误恢复流程。频繁的错误帧表明总线物理层或节点时序存在问题。在报文过滤与ID分配优化中,应避免ID冲突导致的位错误,以及DLC不匹配导致的CRC错误。

2.5 过载帧:接收节点请求延迟

过载帧由接收节点在以下两种情况下发送:

  • 节点内部条件未准备好,无法开始接收下一帧。
  • 在帧间隔期间检测到显性位(非法情况)。

过载帧结构:6位显性过载标志 + 8位隐性过载定界符。过载帧与错误帧的区别在于:过载帧不增加错误计数器,且仅在帧间隔期间发送。

2.6 帧间隔:总线空闲与优先级重置

帧间隔(Interframe Space)用于将前一帧与后续帧分隔开,确保总线状态稳定。帧间隔包含三个场:

帧间隔结构 前一帧 间隔场 3位隐性 总线空闲 任意长度隐性 下一帧 • 间隔场:3位隐性位,用于错误被动节点在发送前等待。 • 总线空闲:任意长度的隐性电平,任何节点检测到空闲后即可开始发送。

2.7 帧类型识别与过滤配置要点

在MCU外设驱动开发中,CAN控制器硬件过滤器需要根据帧类型进行配置。以下是关键配置参数:

/* 标准帧过滤器配置示例(以STM32 bxCAN为例) */
CAN_FilterInitTypeDef filter;
filter.FilterIdHigh = (id << 5) >> 16;   // 11位ID左对齐
filter.FilterIdLow  = (id << 5) & 0xFFFF;
filter.FilterMaskIdHigh = (mask << 5) >> 16;
filter.FilterMaskIdLow  = (mask << 5) & 0xFFFF;
filter.FilterScale = CAN_FilterScale_16bit;
filter.FilterMode  = CAN_FilterMode_IdMask;
filter.FilterFIFOAssignment = CAN_FIFO0;
filter.FilterActivation = ENABLE;
/* 注意:标准帧需设置 FilterBank 的 IDE 位为 0 */
/* 扩展帧过滤器配置示例 */
filter.FilterIdHigh = (id >> 13) & 0xFFFF;  // 29位ID高16位
filter.FilterIdLow  = (id << 3) & 0xFFF8;   // 低13位 + IDE位(1) + RTR位
filter.FilterMaskIdHigh = (mask >> 13) & 0xFFFF;
filter.FilterMaskIdLow  = (mask << 3) & 0xFFF8;
/* 注意:扩展帧必须设置 IDE 位为 1,否则过滤器无法匹配 */
优化建议:在ID分配阶段,建议将标准帧与扩展帧的ID空间分开规划。例如,标准帧ID范围0x000~0x7FF用于高优先级实时控制,扩展帧ID范围0x10000000~0x1FFFFFFF用于诊断和配置。这样可以在硬件过滤器中设置两个独立的过滤器组,分别匹配标准帧和扩展帧,降低CPU负载。

2.8 帧结构对ID分配的影响

理解帧结构后,可以总结出ID分配优化的几个关键约束:

  • 优先级与ID值:ID值越小,优先级越高。关键安全报文(如制动、转向)应分配小ID。
  • 标准帧 vs 扩展帧:标准帧ID空间有限(2048个),扩展帧ID空间充裕(约5.3亿个)。在大型网络中,优先使用扩展帧以避免ID冲突。
  • RTR位影响:远程帧的RTR位为隐性,导致其优先级低于同ID的数据帧。设计时应避免数据帧与远程帧使用相同ID,否则可能引发优先级反转。
  • DLC与数据场:DLC必须与实际数据长度一致。过大的DLC浪费总线带宽,过小的DLC可能导致接收节点数据截断。