3、CAN总线基础:CAN总线物理层、CAN数据帧结构、CAN仲裁机制、CAN错误处理

各位同学,咱们今天聊聊CAN总线。说实话,搞UDS诊断,CAN总线是绕不开的坎。你想想看,诊断报文就是在CAN总线上跑来跑去的。如果不懂CAN,那UDS诊断就是空中楼阁。

我刚开始接触车载诊断时,也犯过迷糊。总觉得UDS是UDS,CAN是CAN,各学各的就行。后来在项目里踩了坑,才明白——不懂CAN的物理特性和仲裁机制,你连诊断超时都查不明白。好,咱们正式开始。

3.1 CAN总线物理层

CAN总线物理层,说白了就是信号怎么在线上跑。它用的是差分信号,两根线:CAN_H和CAN_L。

为什么用差分?抗干扰能力强啊。车里面电磁环境多复杂,你想想看,发动机点火、电机运转,全是噪声源。差分信号一搞,干扰在两根线上同时出现,一减就没了。

关键点:CAN总线有两种电平状态——显性(Dominant)和隐性(Recessive)。显性电平对应逻辑0,隐性电平对应逻辑1。显性会覆盖隐性,这是仲裁的基础。

我记得有一次,客户反映某款车在发动机启动瞬间诊断通信中断。查了半天,发现是CAN收发器的共模抑制能力不够,发动机启动时的共模干扰直接把信号淹没了。后来换了更高等级的收发器,问题解决。

物理层还有几个参数你得记住:

  • 总线终端电阻:120Ω,两端各一个。没有它,信号反射会让你怀疑人生。
  • 最大通信距离:和波特率有关。1Mbps时大概40米,125kbps时可以到500米。车内用,绰绰有余。
  • CAN_H和CAN_L的电压:隐性时约2.5V,显性时CAN_H升到3.5V,CAN_L降到1.5V,压差2V。

我的小建议:做诊断开发时,示波器一定要看CAN_H和CAN_L的差分信号。别只看单端,容易误判。我曾经被单端波形骗过,折腾了两天才发现是探头接地没接好。

3.2 CAN数据帧结构

CAN数据帧,就是报文在总线上跑的样子。标准帧有11位ID,扩展帧有29位ID。UDS诊断一般用标准帧,11位ID够用了。

一个标准数据帧长这样:

SOF + 11位ID + RTR + IDE + r0 + DLC + 数据段(0-8字节) + CRC + ACK + EOF

我来拆开讲:

  • SOF(Start of Frame):1位显性,告诉总线"我要发数据了"。
  • ID(标识符):11位,决定优先级。数值越小,优先级越高。
  • RTR(Remote Transmission Request):区分数据帧和远程帧。诊断一般用数据帧,RTR=0。
  • DLC(Data Length Code):4位,表示数据长度。0到8字节。UDS诊断报文通常用8字节。
  • 数据段:0-8字节,诊断数据就放这里。
  • CRC:15位校验,加1位分隔符。保证数据完整性。
  • ACK:2位。发送方发隐性,接收方如果收到正确的帧,就在ACK Slot位拉显性,表示"我收到了"。
  • EOF:7位隐性,表示帧结束。

注意:UDS诊断报文的数据段,第一个字节通常是服务ID(如0x10、0x22、0x2E等)。后面跟着子功能或数据参数。8字节不够用时,要用到ISO-TP(传输层协议)来分包,这个后面章节会讲。

我习惯在调试时用CAN工具抓一帧报文,然后对照着帧结构一个一个字段看。刚开始可能觉得繁琐,但看多了就熟了。嗯,这里要注意,CRC和ACK部分工具一般会自动处理,你重点看ID、DLC和数据段就行。

3.3 CAN仲裁机制

仲裁,说白了就是多个节点同时发数据时,谁说了算。

CAN总线是"线与"机制。多个节点同时发送,显性位(0)会覆盖隐性位(1)。仲裁的过程就是:每个节点从ID的最高位开始,逐位比较。谁的ID先出现显性位,谁就赢。

举个例子:

节点A的ID是0x7FF(二进制11111111111),节点B的ID是0x100(二进制00100000000)。

从最高位开始比:

  • 第1位:A发1(隐性),B发0(显性)。显性覆盖隐性,B赢。
  • A检测到总线电平和自己发的不一致,立刻退出,转为接收模式。
  • B继续发送剩余位,直到帧结束。

为什么会这样设计?因为诊断报文通常优先级低,不能让诊断干扰了关键控制报文。比如发动机控制报文ID一般是0x100左右,诊断报文ID可能是0x7DF。你想想看,发动机控制比诊断重要多了,仲裁机制保证了关键报文优先通过。

避坑指南:我曾经在项目里遇到过一个问题——诊断仪发送请求后,ECU一直没响应。查了半天,发现是诊断请求ID和某个控制报文的ID冲突了。仲裁时诊断报文总是输,发不出去。后来改了诊断ID,问题解决。所以,ID分配一定要规划好,别和关键控制报文抢优先级。

3.4 CAN错误处理

CAN总线有5种错误类型:

错误类型 说明 检测机制
位错误(Bit Error) 发送方发送的电平和总线上检测到的电平不一致 发送方在发送位的同时监控总线
填充错误(Stuff Error) 连续5个相同电平后,没有插入相反电平 接收方检测位填充规则
CRC错误 接收方计算的CRC和发送方的不一致 接收方校验CRC
格式错误(Form Error) 帧格式中固定位段出现错误电平 接收方检测固定位段
应答错误(ACK Error) 发送方没有收到ACK显性应答 发送方检测ACK Slot

每个CAN节点都有两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。

  • 错误主动(Error Active):TEC<127且REC<127。正常状态,检测到错误就发主动错误帧(6位显性)。
  • 错误被动(Error Passive):TEC>127或REC>127。只能发被动错误帧(6位隐性),且发送前要等待8位隐性位。
  • 总线关闭(Bus Off):TEC>255。节点完全退出总线,不再参与通信。

实战经验:诊断开发时,如果发现ECU突然不响应了,先查TEC和REC。我遇到过一种情况——诊断仪反复发送错误请求,ECU每次收到都回复错误响应,但诊断仪认为响应格式不对,又重发。来回几次,ECU的TEC飙到255,直接总线关闭了。重启ECU才恢复。所以,诊断请求一定要规范,别把ECU"打死"了。

错误恢复机制也很重要。节点检测到错误后,会发送错误帧,然后自动重发被破坏的报文。重发次数没有限制,直到成功或总线关闭。这个机制保证了数据的可靠性,但也可能导致"错误风暴"——一个节点频繁出错,反复重发,把总线带宽占满。

注意:错误风暴在诊断中很常见。比如某个ECU的CAN收发器坏了,一直发错误帧,导致诊断报文发不出去。排查时,用示波器看总线波形,如果看到连续的6位显性错误帧,基本就是有节点出问题了。一个一个拔节点,拔到哪个总线恢复正常,就是哪个的问题。

好,CAN总线基础就讲到这里。下一章咱们聊ISO-TP传输层协议,看看UDS诊断报文是怎么在CAN总线上分包和组包的。到时候你会明白,为什么我说CAN是UDS的基石。