2、CAN协议详解:CAN数据帧结构、CAN远程帧、CAN错误帧、CAN过载帧

CAN协议,说白了就是一套让多个节点在一条总线上有序说话的规则。我刚开始接触CAN时,觉得帧结构挺复杂,但后来发现,只要搞懂四种帧——数据帧、远程帧、错误帧、过载帧,整个协议就通了八成。

咱们先看一张总览图,把这四种帧的关系理清楚。

CAN协议四种帧类型关系图 CAN协议四种帧类型 CAN总线帧类型 数据帧 远程帧 错误帧 过载帧 数据帧和远程帧由用户层产生,错误帧和过载帧由CAN控制器硬件自动触发 理解这四种帧,是调试CAN总线问题的基本功

2.1 数据帧——最常用的帧

数据帧就是用来发送数据的。一个节点把数据打包成帧,广播到总线上,其他节点根据ID决定要不要接收。我做过一个项目,车上十几个ECU全靠数据帧交换信息,谁发什么ID,提前约定好。

数据帧的结构,我习惯分成七段来看:

段名称 位数(标准帧) 说明
帧起始 1 bit 显性电平,同步所有节点
仲裁段 12 bits 包含11位ID + RTR位,决定优先级
控制段 6 bits IDE位、保留位、DLC(数据长度码)
数据段 0~64 bits 实际数据,最多8字节
CRC段 16 bits 15位CRC + 1位CRC界定符
ACK段 2 bits 接收节点回应,确认收到
帧结束 7 bits 隐性电平,表示帧结束

关键点:数据段最多8字节。为什么是8?早期设计时,考虑到汽车控制信号的实时性要求,8字节足够传递大部分传感器和执行器数据。我见过有人非要把大包拆成多个CAN帧发,其实没必要——超过8字节就该考虑用CAN FD了。

标准帧和扩展帧的区别,主要在仲裁段。标准帧11位ID,扩展帧29位ID。我个人的习惯是:能用标准帧就别用扩展帧,因为标准帧的仲裁效率更高,总线利用率也更好。

2.2 远程帧——问别人要数据

远程帧,说白了就是“请求帧”。一个节点发远程帧,告诉另一个节点:“把你的数据发给我。” 远程帧的结构和数据帧几乎一样,唯一的区别是RTR位为隐性(1)。

我记得有一次调试一个电机控制器,它总是不响应我的远程帧请求。查了半天,发现是对方固件里把远程帧处理关掉了。嗯,这里要注意:不是所有CAN节点都会处理远程帧,很多设备只认数据帧。

实战建议:远程帧在实际工程中用得不多。我建议你尽量用数据帧主动上报,而不是靠远程帧去轮询。原因很简单:远程帧会增加总线负载,而且响应时间不可控。

2.3 错误帧——总线出了问题怎么办

错误帧是CAN控制器硬件自动发的,不需要软件干预。一旦节点检测到总线错误,就会立刻发送错误帧,通知所有节点“刚才那帧有问题,别用了”。

错误帧由两部分组成:

  • 错误标志:6个连续显性位(主动错误)或6个连续隐性位(被动错误)
  • 错误界定符:8个连续隐性位

CAN协议定义了五种错误类型:

错误类型 触发条件 我遇到过的案例
位错误 发送节点监控到总线电平与发送不一致 有一次总线短路,发送显性位却读到隐性
填充错误 连续6个相同电平,违反位填充规则 干扰导致位翻转,触发填充错误
CRC错误 接收节点计算的CRC与发送的不一致 波特率不匹配时最常见
形式错误 固定格式位(如界定符)电平错误 硬件时序问题导致
应答错误 发送节点没收到ACK显性位 总线上只有发送节点自己

避坑指南:我曾经在产线上遇到一个批量问题——某批ECU频繁报CRC错误。查到最后发现是晶振精度不够,导致位时序偏差累积。所以,CAN节点的时钟精度一定要控制在1%以内,最好用0.5%的晶振。

2.4 过载帧——我忙不过来了

过载帧,是节点告诉总线“我处理不过来了,慢一点”。它和错误帧长得有点像,但触发原因完全不同。

过载帧的结构:

  • 过载标志:6个连续显性位
  • 过载界定符:8个连续隐性位

触发过载帧的两种情况:

  1. 接收节点内部条件不成熟,比如接收缓冲区满了
  2. 帧间隔期间检测到显性位(这属于总线干扰)

说实话,我在实际项目中很少见到过载帧。现在的CAN控制器缓冲区都比较大,加上合理的软件设计,一般不会触发过载。如果你在调试时频繁看到过载帧,先检查一下接收中断处理是不是太慢了。

2.5 四种帧的对比总结

最后,我用一张表把这四种帧的核心差异列出来,方便你对照:

帧类型 触发方式 数据段 RTR位 用途
数据帧 软件主动发送 有(0~8字节) 显性(0) 传输数据
远程帧 软件主动发送 无 隐性(1) 请求数据
错误帧 硬件自动触发 无 — 通知总线错误
过载帧 硬件自动触发 无 — 请求延迟发送

你想想看,这四种帧其实覆盖了CAN总线通信的所有场景:正常发数据用数据帧,要数据用远程帧,出错了硬件自动发错误帧,忙不过来就发过载帧。搞懂这些,CAN协议的基础就算打牢了。