第4章:数据链路层差异——K线、CAN与传输层的那些事儿
好,咱们进入数据链路层。这一层,说白了就是物理层之上的“规矩制定者”。OBD和UDS在这里的差异,可以说是天壤之别。我个人觉得,搞懂这一层,你才算真正入了诊断协议的门。
4.1 OBD的K线协议(ISO 9141)——老古董,但还在用
先聊聊K线。ISO 9141,也就是我们常说的K线协议。这玩意儿,嗯,有点年头了。我记得我刚入行那会儿,大部分车还都是K线。它用一根线(K线)做双向半双工通信,另一根L线做唤醒。
K线的核心特点:
- 物理层:单线,电压12V(标称),波特率通常10.4 kbps。你没看错,就是10.4k,慢得让人着急。
- 通信方式:半双工。就是说,发的时候不能收,收的时候不能发。跟对讲机似的。
- 寻址方式:物理寻址。每个ECU有一个固定的地址,比如发动机是0x01,ABS是0x02。诊断仪发请求时,目标地址就放在报文里。
- 报文结构:简单。一个字节的Header,一个字节的Data Length,然后是数据,最后是校验和。
K线报文格式(简化版):
| Header (1 Byte) | Data Length (1 Byte) | Data (N Bytes) | Checksum (1 Byte) |
Header里包含了目标地址和源地址。Data Length就是后面跟着多少个数据字节。
避坑指南:我曾经在调试一个老款车型时,K线通信死活不通。查了半天,发现是L线唤醒时序不对。K线协议要求诊断仪先拉低L线至少25ms,然后释放,ECU才会醒来。很多新手会忽略这个唤醒时序,直接发请求,结果就是石沉大海。
4.2 OBD的CAN协议(ISO 15765)——过渡方案,但很实用
后来CAN总线普及了,OBD也得跟上。于是就有了ISO 15765,也就是OBD on CAN。说白了,就是把OBD的那套诊断服务(比如读故障码、读数据流)封装到CAN报文里发出去。
ISO 15765的核心变化:
- 物理层:CAN总线,双线(CAN-H和CAN-L),差分信号。抗干扰能力强多了。
- 波特率:通常250 kbps或500 kbps。比K线快了几十倍。
- 寻址方式:还是物理寻址,但用CAN ID来表示。比如0x7DF是广播地址,0x7E0是诊断仪,0x7E8是发动机ECU。
- 报文结构:CAN标准帧,11位ID。数据场最多8个字节。
你想想看,K线一次只能发几个字节,CAN一次能发8个。效率提升是巨大的。但这里有个问题:OBD的CAN协议,它的传输层其实很简陋。它只支持单帧传输,也就是一帧报文搞定一个请求或响应。如果数据超过8个字节怎么办?对不起,不支持。这就是OBD的局限。
我的经验:在实际项目中,OBD on CAN最常用的就是读故障码(Service 03)和读数据流(Service 01)。因为这些数据通常很小,一帧就能搞定。但如果你想做更复杂的操作,比如刷写ECU,OBD on CAN就无能为力了。
4.3 UDS的CAN传输层(ISO 15765-2)——这才是真正的“传输层”
好,重点来了。UDS的CAN传输层,也就是ISO 15765-2。它跟OBD的CAN协议(ISO 15765)虽然名字像,但完全是两码事。ISO 15765-2,我们通常叫它“CAN TP”(Transport Protocol)。
为什么需要CAN TP?因为UDS的报文可能很长。比如你要上传一个几十KB的固件,或者下载一个几百字节的配置数据。CAN的一帧只能装8个字节,根本装不下。所以需要CAN TP来把长报文拆成多个短帧,再在接收端组装起来。
CAN TP的核心机制:
- 单帧(SF):数据长度 ≤ 7字节(如果使用扩展寻址,则 ≤ 6字节)。直接发,不需要拆包。
- 首帧(FF):数据长度 > 7字节。首帧里包含了总数据长度信息,告诉接收方“我要发一个长报文,总共N个字节”。
- 连续帧(CF):首帧之后,剩下的数据用连续帧发送。每个连续帧带有一个序列号,接收方用来排序。
- 流控制帧(FC):接收方收到首帧后,会回复一个流控制帧。告诉发送方:“我准备好了,你可以发了”或者“慢点,我处理不过来”。
CAN TP的典型交互流程:
诊断仪 -> ECU: 首帧 (FF) [总长度 = 100字节]
ECU -> 诊断仪: 流控制帧 (FC) [允许发送,块大小=0,最小间隔=0]
诊断仪 -> ECU: 连续帧 1 (CF1) [8字节数据]
诊断仪 -> ECU: 连续帧 2 (CF2) [8字节数据]
...
诊断仪 -> ECU: 连续帧 12 (CF12) [最后4字节数据]
注意:块大小(Block Size)和最小间隔(Separation Time)是流控制帧里的关键参数。块大小告诉发送方,每发多少个连续帧就要等一次流控制。最小间隔告诉发送方,两个连续帧之间至少间隔多少毫秒。
避坑指南:我曾经在一个项目中,ECU的接收缓冲区太小,导致连续帧发到一半就溢出了。后来发现是流控制帧里的“块大小”设得太大了。ECU一次只能处理4个连续帧,但诊断仪一口气发了8个。结果就是丢帧,通信失败。所以,流控制帧的参数一定要根据ECU的实际能力来设置,不能想当然。
4.4 核心差异对比表
| 特性 | OBD K线 (ISO 9141) | OBD CAN (ISO 15765) | UDS CAN TP (ISO 15765-2) |
|---|---|---|---|
| 物理层 | 单线,12V,10.4 kbps | 双线差分,250/500 kbps | 双线差分,250/500 kbps |
| 通信方式 | 半双工 | 半双工 | 半双工 |
| 寻址方式 | 物理寻址(字节地址) | 物理寻址(CAN ID) | 物理寻址或功能寻址(CAN ID) |
| 最大数据长度 | 255字节(但实际受限于波特率) | 7字节(单帧) | 4095字节(通过多帧传输) |
| 流控制 | 无 | 无 | 有(流控制帧) |
| 典型应用 | 老车型诊断 | OBD标准诊断 | UDS复杂诊断、刷写 |
看到这个表,你应该明白了。OBD的K线和CAN,都是“轻量级”的。它们的设计目标就是快速读取故障码和数据流,不需要复杂的传输层。而UDS的CAN TP,是“重量级”的。它要支持刷写、配置、在线编程等复杂操作,所以必须有一套完善的拆包、组包、流控制机制。
重要提醒:千万不要把OBD的CAN协议(ISO 15765)和UDS的CAN TP(ISO 15765-2)混为一谈。虽然它们都叫“15765”,但一个是应用层协议,一个是传输层协议。很多初学者会在这里栽跟头。我建议你记住一句话:OBD on CAN是“用CAN线跑OBD服务”,而UDS on CAN是“用CAN TP跑UDS服务”。完全不同的概念。
好了,数据链路层就讲到这里。下一章,我们会进入应用层,看看OBD和UDS的诊断服务到底有什么不同。到时候,我会用实际项目中的例子,给你讲讲那些“坑”。