一、UDS协议概述:协议栈分层、OSI模型映射与诊断服务分类

大家好,我是你们的老朋友。今天咱们正式开始聊UDS诊断协议。

说实话,我刚入行那会儿,面对UDS协议栈也是一头雾水。什么分层、什么服务ID,感觉像天书。但后来我明白了,这东西说白了就是一套“车规级对话规则”。你想想看,ECU和诊断仪之间要通信,总得有个规矩吧?UDS就是这套规矩。

1.1 UDS协议栈分层:从物理层到应用层

UDS协议栈,我习惯把它理解成“七层汉堡”。每一层都有自己的职责,上层依赖下层。咱们从下往上捋一捋。

OSI模型层 UDS对应层 我的理解
第7层:应用层 UDS应用层(服务原语) 诊断仪发什么指令,ECU怎么回应
第6层:表示层 (通常不单独实现) 数据格式转换,UDS里一般合并到应用层
第5层:会话层 (由传输层管理) 建立、维持、终止会话
第4层:传输层 ISO 15765-2(CAN上的传输层) 分包、重组、流控制
第3层:网络层 ISO 15765-2(网络层) 寻址、路由
第2层:数据链路层 CAN控制器(如M_CAN、SJA1000) 帧封装、错误检测
第1层:物理层 CAN收发器(如TJA1040) 电平转换、总线驱动

嗯,这里要注意。实际项目中,我们最常打交道的是第7层(应用层)和第4层(传输层)。物理层和数据链路层,一般由硬件和底层驱动搞定,我们做应用层开发的,很少直接碰。

我的小经验: 刚开始学UDS,别急着啃传输层。先把应用层的服务搞明白,比如0x10(诊断会话控制)、0x22(读取数据)、0x2E(写入数据)。这些是日常开发最常用的。传输层的分包重组,等遇到大数据传输(比如刷写Bootloader)时再深入,效果更好。

1.2 OSI模型映射:UDS是怎么“住进”CAN的?

UDS本身不关心底层用的是什么总线。它只定义“说什么”和“怎么回应”。至于“怎么传过去”,那是CAN、LIN、以太网的事。

但在汽车行业,99%的UDS诊断都跑在CAN总线上。所以咱们重点聊聊UDS over CAN。

CAN报文只有8字节数据场。但UDS的一条诊断请求,可能超过8字节。比如你要读取一串DTC(故障码),或者刷写一段程序。这时候怎么办?

答案就是:ISO 15765-2(俗称CAN-TP,传输层协议)。

它负责把长数据包拆成多个CAN帧,发送出去。接收端再把这些帧重组回来。我举个例子:

// 假设要发送一条12字节的UDS请求
// 原始数据:02 10 03 00 00 00 00 00 00 00 00 00
// 拆成两帧:
// 第一帧(FF):10 0C 02 10 03 00 00 00  (10表示首帧,0C表示总长度12字节)
// 第二帧(CF):21 00 00 00 00 00 00 00  (21表示连续帧,序号1)

你看,第一帧的0x10表示这是首帧,0x0C表示后面还有12字节数据。第二帧的0x21表示这是连续帧,序号为1。接收端收到后,按序号拼回去,就得到了完整的12字节请求。

避坑指南: 我曾经在一个项目中,发现ECU偶尔收不到完整的诊断响应。排查了三天,最后发现是CAN-TP的流控制帧(FC)没处理好。发送端发完首帧后,接收端必须回复FC帧,告诉发送端“你可以继续发了”或者“慢点发”。如果FC帧丢了,发送端就会一直等,导致超时。所以,流控制帧的处理一定要加超时重传机制

1.3 诊断服务分类:功能单元与诊断服务

UDS协议(ISO 14229-1)把诊断服务分成了几大类。我习惯叫它们“功能单元”。每个功能单元下面,有若干个具体的诊断服务。

咱们直接看表,一目了然:

功能单元 服务ID(SID) 服务名称 我常用的场景
诊断和通信管理 0x10 诊断会话控制 切换会话模式(默认、扩展、编程)
0x11 ECU复位 硬复位、钥匙复位
0x3E 测试仪在线 保持会话活跃,防止超时
数据传输 0x22 读取数据 读DID(数据标识符)
0x2E 写入数据 写DID,比如标定参数
0x23 读取内存 按地址读内存,刷写时常用
存储数据传输 0x14 清除诊断信息 清DTC
0x19 读取DTC信息 读故障码、快照、扩展数据
输入输出控制 0x2F 输入输出控制 强制驱动某个执行器,比如开风扇
远程激活 0x31 例程控制 启动、停止、检查例程
上传/下载 0x34 请求下载 刷写前置步骤
0x36 传输数据 实际数据传输
0x37 请求传输退出 结束传输

你看,每个服务都有唯一的SID(Service ID)。诊断仪发请求时,第一个字节就是SID。ECU回应时,会把SID的最高位置1,表示这是响应。比如请求是0x22,正常响应就是0x62。

重点来了: 我建议你把0x10、0x22、0x2E、0x19、0x14这五个服务背下来。它们覆盖了90%的日常诊断需求。其他服务,用到的时候再查表,完全来得及。

为什么会这样?因为大多数诊断任务无非就是:

  • 切换会话(0x10)
  • 读数据(0x22)
  • 写数据(0x2E)
  • 读故障码(0x19)
  • 清故障码(0x14)

你想想看,是不是这个理?

好了,这一章咱们把UDS的协议栈分层、OSI模型映射、以及服务分类都捋了一遍。下一章,我会带大家深入0x10服务——诊断会话控制。这可是所有诊断流程的“大门”。咱们到时候见。