第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的诊断服务到底有什么不同。到时候,我会用实际项目中的例子,给你讲讲那些“坑”。