3. UDS服务基础:服务ID(SID)分类、请求与响应机制、子功能与数据参数

好,咱们进入第三章。这一章是整个UDS诊断协议的基石,说白了就是「怎么跟ECU说话,ECU又怎么回你」。我见过不少新手,上来就背SID列表,结果真到项目里连个请求报文都拼不对。别急,咱们一步步来。

3.1 服务ID(SID)是什么?

服务ID,全称Service Identifier,就是诊断请求的第一个字节。ECU看到这个字节,就知道你要干嘛。

举个例子:你发 10 01,ECU就知道你要切换会话模式。这里的 0x10 就是SID。我个人习惯把SID理解成「指令码」,跟单片机里的指令集一个道理。

UDS标准(ISO 14229-1)把SID分成了六大类,我整理了一张表,你存着,以后查起来方便:

SID范围 服务类别 典型服务
0x10 - 0x3E 诊断和通信管理 10(诊断会话控制)、11(ECU复位)、3E(Tester Present)
0x22 - 0x2E 数据传输 22(按ID读取数据)、2E(按ID写入数据)
0x14 - 0x19 存储数据传输 14(清除诊断信息)、19(读取DTC信息)
0x27 - 0x27 输入输出控制 2F(输入输出控制)
0x28 - 0x3D 远程激活 31(例程控制)、34(请求下载)
0x84 - 0x85 安全 27(安全访问)
我的小技巧: 别死记硬背。你只要记住几个常用的:0x10(会话控制)、0x22(读数据)、0x2E(写数据)、0x19(读故障码)、0x27(安全解锁)。剩下的用到再查,项目做多了自然就记住了。

3.2 请求与响应机制

UDS的通信模式很简单,就是「一问一答」。你发一个请求,ECU必须回一个响应。但这里有个坑——响应分两种:肯定响应否定响应

3.2.1 肯定响应

ECU成功执行了你的请求,就会回肯定响应。格式是:SID + 0x40 + 数据。

比如你发 22 F1 90(读取VIN码),ECU回 62 F1 90 4C 53 56 00 ...。这里的 0x62 就是 0x22 + 0x40,表示「你的读数据请求我收到了,这是你要的数据」。

嗯,这里要注意:肯定响应的第一个字节永远是 请求SID + 0x40。这是UDS协议的铁律,别搞错了。

3.2.2 否定响应

ECU执行失败了,就会回否定响应。格式是:0x7F + 请求SID + 否定响应码(NRC)。

举个例子:你发 22 F1 90,但当前会话模式不允许读数据,ECU就回 7F 22 7F。这里的 0x7F 是固定前缀,0x22 是请求的SID,0x7F 是NRC,表示「服务不支持」。

核心记忆点:
  • 肯定响应:SID + 0x40
  • 否定响应:0x7F + SID + NRC
我曾经踩过的坑: 有一次我写测试脚本,把否定响应的格式记反了,以为否定响应也是 SID + 0x7F。结果解析出来的数据全是乱的,排查了半天才发现是格式搞错了。记住,否定响应的第一个字节永远是 0x7F,不是别的。

3.3 子功能与数据参数

很多UDS服务都支持子功能。子功能就是SID后面的第二个字节,用来细分这个服务要干什么。

3.3.1 子功能的结构

子功能字节的高位(bit 7)有个特殊含义:

  • bit 7 = 0:表示这是一个请求,ECU需要执行并回复
  • bit 7 = 1:表示这是一个响应,ECU回复时会把bit 7置1

你想想看,这个设计是不是很巧妙?ECU收到请求后,直接把子功能的bit 7置1,就变成了响应。省去了额外的判断逻辑。

举个例子:10 01 是请求进入默认会话。ECU回复 50 01,这里的 0x50 = 0x10 + 0x40,而子功能 0x01 的bit 7被置1,变成了 0x81?不对,这里要注意:子功能bit 7置1只适用于某些服务,比如0x10、0x11、0x27等。对于0x22这种没有子功能的服务,就不适用。

我个人习惯把子功能理解成「菜单选项」。比如0x10服务(诊断会话控制)的子功能:

  • 01:默认会话
  • 02:编程会话
  • 03:扩展会话

你选哪个,ECU就进哪个模式。

3.3.2 数据参数

数据参数就是SID和子功能后面的字节。它们提供了执行服务所需的额外信息。

比如0x22服务(按ID读取数据):

请求:22 F1 90
      ^^ ^^ ^^
      || || +-- 数据标识符(高字节)
      || +---- 数据标识符(低字节)
      +------- SID

这里的 F1 90 就是数据参数,告诉ECU你要读哪个数据。ECU根据这个ID去查内部的数据表,找到对应的值返回给你。

再比如0x2E服务(按ID写入数据):

请求:2E F1 90 01 02 03 04
      ^^ ^^ ^^ ^^^^^^^^^^^^
      || || || +-- 要写入的数据
      || || +---- 数据标识符(低字节)
      || +------- 数据标识符(高字节)
      +---------- SID

这里的数据参数就复杂了,既有数据标识符,又有要写入的数据值。

我的经验: 刚开始接触UDS时,我总搞不清哪些字节是数据参数。后来我总结了一个规律:SID决定服务类型,子功能决定具体操作,剩下的全是数据参数。你按这个思路去解析报文,基本不会错。

3.4 实战:拼一个完整的诊断请求

咱们来拼一个真实的诊断请求。假设我们要读取ECU的VIN码(数据标识符0xF190):

  1. 确定SID:读数据用0x22
  2. 确定数据参数:VIN码的ID是0xF190,所以数据参数是 F1 90
  3. 拼请求22 F1 90

ECU收到后,如果成功,会回复:

62 F1 90 4C 53 56 00 00 00 00 00 00 00 00 00 00 00
^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|| || || +-- VIN码数据(ASCII编码)
|| || +---- 数据标识符(低字节)
|| +------- 数据标识符(高字节)
+---------- 肯定响应SID(0x22 + 0x40)

如果失败,比如当前会话不允许读数据,ECU会回复:

7F 22 7F
^^ ^^ ^^
|| || +-- NRC(服务不支持)
|| +---- 请求的SID
+------- 否定响应前缀
总结一下:
  • SID是诊断请求的「指令码」,ECU靠它识别你要干嘛
  • 肯定响应 = SID + 0x40,否定响应 = 0x7F + SID + NRC
  • 子功能是SID的「菜单选项」,bit 7用于区分请求和响应
  • 数据参数是SID和子功能后面的字节,提供执行服务所需的额外信息

这一章的内容就到这里。下一章咱们会深入讲一个最常用的服务——0x10诊断会话控制。到时候我会结合项目中的实际案例,告诉你不同会话模式到底该怎么用。咱们下章见。