3、CAN总线基础:CAN总线工作原理,CAN报文结构(ID、DLC、Data),CAN与UDS的关系

好,咱们进入第三讲。说实话,CAN总线是UDS协议的“腿”。没有CAN,UDS哪也去不了。很多刚入行的朋友一上来就啃UDS的规范,结果发现报文发不出去,或者收不到响应,卡在那里半天。我当年也干过这事儿,后来才明白,先把CAN总线搞透,UDS学起来就是水到渠成的事。

3.1 CAN总线工作原理——它到底是怎么“说话”的?

CAN总线,全称是Controller Area Network。它最早是博世公司为汽车开发的。你想想看,一辆车里有几十个ECU,发动机、变速箱、ABS、气囊……它们之间要互相通信。如果每个ECU都拉一根线到另一个ECU,那线束比车还重。CAN总线的出现,就是为了解决这个问题——用两根线,把所有节点挂上去。

这两根线,一根叫CAN_H,一根叫CAN_L。它们传输的是差分信号。什么意思?就是逻辑“1”和“0”不是靠一根线的电压高低来判断,而是看两根线的电压差。这样做的好处是抗干扰能力强。我在做EMC测试时深有体会,别的总线被干扰得乱七八糟,CAN总线依然稳如老狗。

CAN总线的工作方式,我总结为三个关键词:多主、广播、仲裁

  • 多主:总线上任何一个节点都可以主动发消息,没有“老大”来分配时间片。谁想说话,谁就开口。
  • 广播:一个节点发消息,所有节点都能收到。但节点会判断这条消息是不是“我该听的”,不是就忽略。
  • 仲裁:如果两个节点同时发消息,怎么办?CAN总线通过ID来仲裁。ID越小,优先级越高。说白了,就是“谁的数字小,谁先走”。

核心要点:CAN总线的仲裁机制是非破坏性的。高优先级的节点在发送时,低优先级的节点会自动退出发送,转为接收。整个过程不会损坏任何数据。这一点非常巧妙。

我曾经在调试一个多节点系统时,发现某个节点总是发不出消息。查了半天,原来是它的ID设得太大了,每次都被别的节点“挤”下去。嗯,这里要注意,ID分配是个技术活,不是随便写的。

3.2 CAN报文结构——ID、DLC、Data,一个都不能少

CAN报文,说白了就是一串数据。但这一串数据里,每个字段都有它的意义。咱们以最常用的标准帧(11位ID)为例,来看看它的结构。

字段 长度 说明
SOF 1 bit 帧起始,标志报文开始
ID 11 bits 标识符,决定优先级
RTR 1 bit 远程帧标志,0为数据帧
IDE 1 bit 扩展帧标志,0为标准帧
DLC 4 bits 数据长度,0~8字节
Data 0~64 bits 实际数据,最多8字节
CRC 15 bits 校验码,保证数据完整性
ACK 2 bits 应答位,接收节点确认
EOF 7 bits 帧结束

咱们重点看三个字段:ID、DLC、Data。因为UDS协议主要跟它们打交道。

3.2.1 ID——报文的“身份证”

ID决定了这条报文在总线上的优先级。ID越小,优先级越高。在UDS中,ID还用来区分是“请求”还是“响应”。比如,诊断请求的ID通常是0x7DF,而响应的ID是0x7E8。我习惯把ID看作“门牌号”,你要找哪个ECU,就发对应的ID。

3.2.2 DLC——数据长度

DLC告诉接收方,Data字段里有多少个字节。范围是0到8。注意,DLC可以小于8,但Data字段里剩下的字节会被忽略。我在项目中遇到过一个问题:发送方DLC设成了8,但实际只用了3个字节,接收方却把后面5个字节的垃圾数据也解析了,结果出了bug。所以,DLC一定要和实际数据长度一致。

3.2.3 Data——真正的“干货”

Data字段最多8个字节。UDS的请求和响应,就塞在这8个字节里。比如,你要读取ECU的版本号,UDS请求可能是“22 F1 90”,这3个字节就放在Data里。如果数据超过8个字节,就需要用多帧传输了。这个后面会讲。

个人经验:刚开始学CAN时,我总记不住DLC和Data的区别。后来我这样理解:DLC是“信封上写的页数”,Data是“信封里装的纸”。页数写错了,纸就数不对。

3.3 CAN与UDS的关系——它们是怎么“合作”的?

这个问题,我经常被问到。说白了,CAN是“运输工具”,UDS是“运输的货物”。CAN负责把数据从一个ECU搬到另一个ECU,而UDS定义了这些数据是什么含义、该怎么处理。

你可以这样理解:

  • CAN:相当于快递员。他只知道把包裹从A送到B,至于包裹里是什么,他不关心。
  • UDS:相当于包裹里的物品清单和操作手册。它告诉你,这个包裹是“读取故障码”还是“写入配置参数”。

在实际的汽车诊断中,UDS的请求和响应,都是通过CAN报文来传输的。具体来说:

  1. 诊断仪(Tester)发送一个CAN报文,ID是诊断请求ID,Data字段里放着UDS请求。
  2. ECU收到后,解析Data字段里的UDS请求,执行相应的操作。
  3. ECU再发送一个CAN报文,ID是诊断响应ID,Data字段里放着UDS响应。

举个例子,读取ECU的软件版本号:

// 诊断仪发送的CAN报文
ID: 0x7DF
DLC: 0x03
Data: 0x22 0xF1 0x90  // 这是UDS的“读取数据”请求

// ECU响应的CAN报文
ID: 0x7E8
DLC: 0x06
Data: 0x62 0xF1 0x90 0x01 0x02 0x03  // 这是UDS的响应,版本号是1.2.3

避坑指南:我曾经在调试时,发现ECU一直不响应。查了半天,原来是CAN报文的ID搞反了。诊断仪发的是0x7DF,但ECU监听的是0x7E8。嗯,这里要注意,ID必须一一对应,否则就是“鸡同鸭讲”。

所以,学UDS之前,一定要先把CAN总线的基础打牢。你不需要成为CAN专家,但至少要能看懂CAN报文,知道ID、DLC、Data是什么意思。否则,后面学UDS的会话控制、安全访问、故障码读取,都会觉得云里雾里。

我个人习惯,在开始一个新项目时,先用CAN工具抓一下总线上的报文,看看ID是怎么分配的,DLC是不是正确。这花不了几分钟,但能避免很多低级错误。你想想看,如果连CAN报文都发不对,UDS学得再好又有什么用呢?

好,这一讲就到这里。下一讲,咱们正式进入UDS协议的核心——服务标识符(SID)。