3. CAN数据链路层:CAN帧的种类与帧格式

数据链路层,说白了就是CAN通信的“交通规则”。它规定了数据怎么打包、怎么发送、怎么避免冲突。我刚开始接触CAN时,总觉得这层太抽象,后来调了几次总线,才明白这些帧类型就是日常打交道的“基本单元”。

3.1 CAN帧的四种类型

CAN总线上跑的消息,一共就四种帧。你想想看,就像马路上的车,有载货的、有空跑的、有出事故的、还有临时管控的。CAN帧也是这个道理。

帧类型 英文名 主要用途 谁发起的
数据帧 Data Frame 携带实际数据从发送器到接收器 发送节点
远程帧 Remote Frame 请求某个ID的数据,自己不携带数据 接收节点
错误帧 Error Frame 检测到总线错误时主动报告 任何节点
过载帧 Overload Frame 接收节点忙不过来,请求延迟发送 接收节点

核心要点:数据帧和远程帧是“正常通信”用的,错误帧和过载帧是“异常处理”用的。调试CAN总线时,80%的时间你都在看数据帧和错误帧。

3.2 数据帧(Data Frame)—— 最常用的帧

数据帧就是“拉货的车”。它负责把传感器数据、控制指令从一个节点传到另一个节点。我个人习惯把数据帧的结构拆成七段来记,这样分析报文时一眼就能看出问题。

3.2.1 数据帧的七段结构

  1. 帧起始(SOF):1个显性位,告诉总线“我要开始发了”。
  2. 仲裁段:包含ID和RTR位,决定谁能抢到总线。
  3. 控制段:包含IDE位、保留位和DLC(数据长度码)。
  4. 数据段:0~8字节的实际数据,这才是我们真正关心的。
  5. CRC段:15位CRC校验码+1位CRC界定符,保证数据没被干扰。
  6. ACK段:接收节点回应“我收到了”。
  7. 帧结束(EOF):7个隐性位,表示帧结束。

我的经验:调试时我最先看DLC(数据长度码)。如果DLC是8但实际只用了2个字节,说明设计时预留了空间。如果DLC是0但数据段还有值,那八成是协议栈配置错了——我曾经被这个问题坑过一整天。

3.3 远程帧(Remote Frame)—— 请求数据的“空车”

远程帧很有意思,它自己不拉货,只是告诉某个节点:“把你的数据发给我”。它的结构和数据帧几乎一样,唯一的区别是RTR位为隐性(1)。

为什么会这样?因为远程帧不需要数据段,所以DLC通常为0。但注意,DLC可以不为0,只是数据段不包含有效数据。

避坑指南:我曾经在一个项目中,远程帧的DLC写成了8,结果接收节点以为要发8字节数据,实际只发了2字节,导致CRC校验一直不过。后来查了三天才发现是DLC没对齐。记住:远程帧的DLC必须与对应数据帧的DLC一致。

3.4 错误帧(Error Frame)—— 总线的“报警器”

错误帧是CAN总线自我保护的机制。任何节点检测到错误,都会立即发送错误帧。它由两部分组成:

  • 错误标志:6个连续相同位(显性或隐性,取决于错误类型)。
  • 错误界定符:8个隐性位。

错误帧一出现,所有节点都会停止当前发送,重新仲裁。嗯,这里要注意:频繁的错误帧说明总线有问题,可能是终端电阻不对、波特率不匹配、或者线缆干扰太大。

实战判断:用CAN分析仪抓包时,如果看到大量错误帧,先检查终端电阻(标准是120Ω,两端各一个)。我遇到过好几次,都是因为终端电阻虚焊导致总线反射,错误帧满天飞。

3.5 过载帧(Overload Frame)—— 接收节点的“缓一缓”

过载帧用得比较少,但关键时刻能救命。当接收节点处理不过来时,它会发送过载帧,告诉发送节点“我忙,你等会儿再发”。

过载帧的结构和错误帧很像:6个显性位+8个隐性位。区别在于,过载帧只在帧间空间(Interframe Space)发送,不会打断正在进行的帧传输。

3.6 标准帧与扩展帧

CAN 2.0规范定义了两种帧格式:标准帧和扩展帧。区别就在ID长度上。

对比项 标准帧 扩展帧
ID长度 11位 29位
可用的ID数量 2^11 = 2048个 2^29 = 5.36亿个
IDE位 显性(0) 隐性(1)
帧长度 较短,效率高 较长,灵活性高
典型应用 J1939、CANopen 自定义协议、多节点系统

你想想看,11位ID只有2048个,在乘用车里勉强够用。但到了工程机械、船舶这些动辄上百个节点的系统,29位ID就很有必要了。我做过一个农机项目,用了扩展帧,每个ECU分配一个独立ID范围,调试时一眼就能看出是哪个节点在发数据。

3.7 知识体系总览

下面这张图把CAN帧的种类和格式串起来了。我建议你把它存下来,以后分析报文时对照着看。

CAN帧种类与帧格式知识体系 CAN帧 数据帧 远程帧 错误帧 过载帧 7段结构 0~8字节数据 RTR位=隐性 无数据段 错误标志+界定符 6+8位结构 帧间空间发送 不打断当前帧 帧格式 标准帧(11位ID) 扩展帧(29位ID) IDE位=显性(0) 典型:J1939、CANopen IDE位=隐性(1) 典型:自定义协议 数据帧和远程帧 共用此分类

个人建议:刚开始学CAN时,先把数据帧的标准格式吃透。11位ID、8字节数据、CRC校验——这三个概念搞明白了,后面扩展帧、远程帧都是锦上添花。我当年就是先拿一个标准帧的报文反复拆解,一周后看其他帧就豁然开朗了。