4. UDS服务与子服务:服务分类与SID/SubFunction详解

好,咱们今天聊聊UDS服务的分类。说实话,刚接触UDS那会儿,我也被那一堆SID搞得头晕。后来做项目多了,慢慢就摸清了门道。UDS服务其实就五大类,每一类都有自己的脾气。

4.1 UDS服务的五大分类

UDS协议里,服务按功能分成五组。我个人习惯把这五组记成:诊断通信、数据传输、存储传输、输入输出、远程激活。你想想看,一辆车上的ECU,无非就是跟它说话、读写数据、管理存储、控制引脚、远程干点啥——正好对应这五类。

分类 功能描述 典型SID
诊断与通信管理 建立/维护诊断会话、安全访问、通信控制 0x10, 0x27, 0x28, 0x3E
数据传输 读写ECU内部数据(DID) 0x22, 0x23, 0x2E
存储数据传输 读写DTC、清除故障码 0x14, 0x19, 0x2F
输入输出控制 强制控制ECU的物理引脚 0x2F, 0x30
远程激活 远程启动例程、下载程序 0x31, 0x34, 0x36, 0x37

核心要点:每个SID就是一个服务ID,0x开头,一个字节。子服务(SubFunction)是跟在SID后面的第二个字节,用来细化操作。

4.2 诊断与通信管理类服务

这类服务是诊断会话的“门卫”。我记得第一次做AURIX项目时,上来就发0x22读数据,结果ECU死活不理我。后来才发现——必须先发0x10进入扩展会话模式。

常见的几个服务:

  • 0x10 诊断会话控制:切换会话模式(默认、编程、扩展)。子服务0x01=默认,0x02=编程,0x03=扩展。
  • 0x27 安全访问:解锁受保护的功能。需要种子-密钥交换。
  • 0x28 通信控制:开启/关闭某些网络通信。
  • 0x3E 测试仪在线:俗称“心跳包”,防止ECU自动退出诊断会话。

我的经验:0x3E这个服务特别容易被忽略。我曾经调试一个项目,ECU总是莫名其妙退出诊断模式,查了半天才发现是测试仪没发心跳包。嗯,从那以后我写代码第一件事就是加个定时器定期发0x3E。

4.3 数据传输类服务

说白了,这类服务就是读写ECU内部的数据。数据通过DID(数据标识符)来寻址,每个DID对应一个特定的参数,比如ECU序列号、软件版本、传感器值。

  • 0x22 按标识符读取数据:最常用的读服务。发SID+DID,ECU返回数据。
  • 0x2E 按标识符写入数据:写服务。需要先进入编程会话并解锁。
  • 0x23 按地址读取内存:直接读物理地址,一般用于Bootloader。

举个例子,读ECU序列号:

请求:22 F1 90
响应:62 F1 90 01 02 03 04 05 06 07 08

这里0xF190就是DID,响应里的62是SID+0x40(表示成功响应),后面跟着8字节序列号。

注意:0x23服务很危险。我曾经见过有人用0x23读内存时地址写错了,直接导致ECU死机。所以,非必要别用0x23,用0x22更安全。

4.4 存储数据传输类服务

这类服务专门处理故障码(DTC)。做诊断开发,DTC是绕不开的。

  • 0x14 清除诊断信息:清除所有DTC。子服务0xFF表示清除所有。
  • 0x19 读取DTC信息:功能很丰富,子服务很多。比如0x01=读取当前DTC数量,0x02=读取DTC列表,0x0A=读取DTC快照。
  • 0x2F 输入输出控制:这个服务其实跨了两类,既算存储类也算IO类。它用来控制DTC的启用/禁用。

我个人觉得0x19是最复杂的服务之一。它的子服务多达十几个,每个子服务还有不同的参数格式。我建议你先把0x01和0x02搞明白,其他的慢慢来。

4.5 输入输出控制类服务

这类服务用来强制控制ECU的物理引脚。比如让某个继电器吸合、让某个LED点亮。做硬件测试时特别有用。

  • 0x2F 输入输出控制:控制某个DID对应的输出。子服务有0x00=强制值、0x01=短时控制等。
  • 0x30 周期性传输数据:让ECU周期性地发送某个DID的数据,省得测试仪一直发请求。

避坑指南:我曾经用0x2F控制一个风扇继电器,结果忘了设置超时时间,风扇一直转着停不下来。后来我养成了习惯——每次用0x2F控制输出,一定同时设置一个定时器,超时后自动恢复默认状态。

4.6 远程激活类服务

这类服务用来执行ECU内部的程序或下载固件。说白了就是“远程干大事”。

  • 0x31 例程控制:启动/停止ECU内部的某个例程。比如擦除Flash、校验CRC。子服务0x01=启动,0x02=停止,0x03=查询结果。
  • 0x34 请求下载:开始固件下载流程。告诉ECU要下载多少数据。
  • 0x36 传输数据:实际传输固件数据块。
  • 0x37 请求传输退出:结束下载,ECU开始校验和重启。

你想想看,0x34、0x36、0x37这三个服务配合起来,就是完整的固件升级流程。我在AURIX上做过好几次OTA升级,核心逻辑就是这三个服务来回调用。

4.7 SID与SubFunction的关系

每个UDS服务都有一个SID(1字节)。有些服务需要子服务(SubFunction),有些不需要。

需要子服务的服务:比如0x10(会话控制)、0x27(安全访问)、0x31(例程控制)。子服务放在请求的第二字节。

不需要子服务的服务:比如0x22(读数据)、0x2E(写数据)。这些服务直接跟DID打交道。

举个例子,0x10服务:

请求:10 03
响应:50 03 00 32 00 C8

这里0x10是SID,0x03是子服务(表示扩展会话)。响应里0x50=0x10+0x40,表示成功。后面跟着会话超时时间等参数。

小技巧:判断一个服务有没有子服务,看它的SID是奇数还是偶数。一般来说,奇数SID(如0x11、0x31)有子服务,偶数SID(如0x22、0x2E)没有。但这只是经验规律,不是绝对的,还是要查协议标准。

4.8 总结一下

UDS服务分类其实不难,记住五类就行。SID是服务的“身份证”,SubFunction是服务的“操作指令”。做AURIX开发时,我建议你先把0x10、0x22、0x2E、0x19、0x31这几个服务搞熟,因为项目里80%的场景都用得到它们。

嗯,下一章咱们会深入讲每个服务的报文格式和AURIX上的代码实现。到时候我会拿实际项目中的代码片段来演示,保证你看完就能上手写。