3. CAN总线数据链路层:帧结构与仲裁机制
数据链路层,说白了就是CAN总线的“交通规则”。物理层只管把0和1发到线上,但这一层才真正决定了谁能说话、说什么、说错了怎么办。我刚开始接触CAN时,总觉得帧结构很枯燥,直到有一次调试一个电机控制器,发现报文老是丢——最后查出来是帧ID配错了。嗯,从那以后我再也不敢小看这一层了。
3.1 CAN帧结构:标准帧 vs 扩展帧
CAN总线上的数据以“帧”为单位传输。每一帧就像一封信,有信封(帧头)、正文(数据)、和校验(CRC)。CAN 2.0规范定义了两种帧格式:标准帧和扩展帧。
| 对比项 | 标准帧 (CAN 2.0A) | 扩展帧 (CAN 2.0B) |
|---|---|---|
| ID长度 | 11位 | 29位 |
| 可标识节点数 | 2048个 | 5.36亿个 |
| 帧头开销 | 较小(47位) | 较大(67位) |
| IDE位 | 0(显性) | 1(隐性) |
| 兼容性 | 所有CAN控制器 | 仅2.0B控制器 |
3.2 帧类型详解
CAN总线定义了四种帧类型。你想想看,就像马路上有不同种类的车:私家车、公交车、救护车、洒水车。每种帧干的事不一样。
3.2.1 数据帧
数据帧是干活的主力。它负责把数据从发送节点传到接收节点。一个标准数据帧的完整结构如下:
SOF + 11位ID + RTR + IDE + r0 + DLC + 0~8字节数据 + CRC + ACK + EOF
关键字段说明:
- SOF (Start of Frame):1位显性,告诉所有节点“我要发帧了”
- ID:标识符,决定优先级(数值越小优先级越高)
- RTR (Remote Transmission Request):数据帧中为0(显性)
- DLC (Data Length Code):4位,表示数据字节数(0~8)
- 数据段:0~8字节,实际载荷
- CRC:15位校验 + 1位定界符
- ACK:2位(应答槽 + 定界符)
- EOF (End of Frame):7位隐性
3.2.2 远程帧
远程帧是“请求帧”。节点A发一个远程帧,意思就是“节点B,请把你的数据发给我”。远程帧和数据帧结构几乎一样,唯一的区别是RTR位为1(隐性)。
远程帧没有数据段,但DLC必须填上请求的数据长度。比如你请求8字节数据,DLC就写8。
3.2.3 错误帧
错误帧是CAN总线的“警报器”。任何节点检测到错误,就会立刻发送错误帧。错误帧由两部分组成:
- 错误标志:6个连续相同位(显性或隐性,取决于错误类型)
- 错误定界符:8个隐性位
错误帧一旦发出,当前正在传输的帧就会被强制终止。所有节点都会丢弃这个帧,然后重新仲裁。
3.2.4 过载帧
过载帧是“慢点,我跟不上了”的信号。当接收节点来不及处理数据时,它会发送过载帧,要求发送方延迟发送。过载帧的结构和错误帧类似,但触发条件不同。
过载帧在实际项目中用得不多。我做了这么多年,只在一些低速的工业控制总线上见过。在高速车载网络中,过载帧的出现往往意味着系统设计有问题——要么是接收缓冲区太小,要么是中断处理太慢。
3.3 仲裁机制:CSMA/CR
CSMA/CR 的全称是 Carrier Sense Multiple Access with Collision Resolution,翻译过来就是“载波监听多路访问/冲突解决”。
说白了,CAN总线的仲裁机制就是:谁优先级高,谁先说话。
3.3.1 工作原理
- 监听:每个节点在发送前,先监听总线是否空闲
- 发送:总线空闲时,节点开始发送帧(从SOF开始)
- 逐位仲裁:多个节点同时发送时,每个节点逐位比较自己的ID和总线上的电平
- 胜负判定:发送显性位(0)的节点获胜,发送隐性位(1)的节点自动退出
3.3.2 仲裁过程图解
3.3.3 为什么CAN能做到无损仲裁?
这个问题我当年想了很久。以太网用的是CSMA/CD,冲突了就要退避重发,效率低。CAN为什么不用退避?
原因在于CAN总线的电气特性:显性位(0)会覆盖隐性位(1)。多个节点同时发送时,只要有一个节点发0,总线上就是0。发送1的节点发现总线和自己发的不一致,就知道自己输了,立刻停止发送。
整个过程在几个微秒内完成,而且胜出的节点可以继续发送完整帧,没有任何时间浪费。这就是“无损位仲裁”的精髓。
3.4 帧间空间
帧和帧之间需要一段“休息时间”,叫做帧间空间(Interframe Space)。它由三部分组成:
- 间歇场:3个隐性位
- 总线空闲:任意长度的隐性位(直到有节点开始发送)
- 暂停发送场:仅被动错误节点需要,8个隐性位
帧间空间的作用是给接收节点一点时间处理刚收到的帧,也为下一次仲裁做好准备。
3.5 本章小结
| 知识点 | 一句话总结 |
|---|---|
| 标准帧 vs 扩展帧 | 11位ID够用就用标准帧,节点多就用扩展帧 |
| 数据帧 | 主力帧,带0~8字节数据 |
| 远程帧 | 请求帧,无数据,RTR=1 |
| 错误帧 | 警报器,检测到错误立刻发送 |
| 过载帧 | “慢点”,接收方忙不过来时发送 |
| CSMA/CR仲裁 | ID越小优先级越高,无损仲裁,胜者继续 |