3、UDS服务分类:诊断服务分类、强制服务与可选服务、服务ID(SID)与子功能

好,咱们接着聊。上一章我们把UDS的七层模型和报文结构理清了,相当于拿到了诊断通信的“交通规则”。但光有规则不行,你还得知道路上跑的是什么“车”。这一章,我们就来聊聊这些“车”——也就是UDS的服务。

我个人习惯把UDS服务比作一个工具箱。你想想看,修车师傅不可能只带一把扳手,他得有螺丝刀、万用表、示波器。UDS也一样,它定义了几十种服务,每种服务干一种特定的活。但这么多服务,不可能全用上,所以就有了分类,有了强制和可选的区别。

3.1 诊断服务分类:按功能领域划分

UDS协议(ISO 14229-1)把服务分成了六大类,或者说六个功能单元。这就像把工具箱里的工具按用途分成了“拧螺丝组”、“测电压组”一样。我刚开始学的时候,觉得这分类有点死板,但后来在项目里发现,按这个分类去查协议,效率高得多。

功能单元 服务ID范围(十六进制) 典型服务举例 一句话说明
诊断和通信管理 0x10 - 0x3E 10(诊断会话控制)、3E(Tester Present) 管“握手”和“保活”的
数据传输功能单元 0x22 - 0x2E 22(读取数据)、2E(写入数据) 读写ECU内部的数据
存储数据传输功能单元 0x14 - 0x19 14(清除诊断信息)、19(读取DTC信息) 处理故障码的
输入输出控制功能单元 0x2F - 0x31 2F(输入输出控制) 强制让某个引脚输出高/低电平
远程激活功能单元 0x31 - 0x3D 31(例程控制) 执行一段写好的程序
上传下载功能单元 0x34 - 0x37 34(请求下载)、36(传输数据) 刷写软件用的

你看,这个分类很清晰。比如你想让ECU执行一个自检动作,那就去“远程激活功能单元”里找31服务。你想读个电压值,就去“数据传输功能单元”里找22服务。嗯,这里要注意,服务ID的范围不是连续的,中间有空号,那些是保留给将来扩展用的。

3.2 强制服务与可选服务:哪些是必须实现的?

这个问题,我在项目里被问过无数次:“王工,UDS服务这么多,我们到底要实现哪些?”

答案是:看你的ECU是什么角色,以及你的客户(主机厂)要求什么。

UDS协议本身定义了一些“强制服务”,说白了就是,只要你的ECU宣称支持UDS,这几个服务你就必须得支持。否则,诊断仪连上来,连最基本的握手都做不了。

核心强制服务(所有ECU必须支持):

  • 10 服务(诊断会话控制):至少支持默认会话(01)。这是ECU上电后的第一个状态。
  • 3E 服务(Tester Present):用于保持非默认会话(比如编程会话)不超时。没有这个,会话几秒钟就掉了。
  • 27 服务(安全访问):当需要执行写数据、刷写等敏感操作时,必须先通过这个服务的“解锁”流程。

除了这三个,其他服务基本都是可选的。但实际项目中,主机厂会有一份“诊断规范”,里面会列出该车型所有ECU必须实现的服务列表。比如,一个发动机控制器,通常必须实现22/2E(读写数据)、19/14(读写故障码)、31(例程控制,比如执行喷油嘴清洗)。而一个车窗控制器,可能只需要22/2E和19就够了。

我的经验: 我建议你在设计软件架构时,把强制服务做成一个“基础模块”,任何项目都直接复用。可选服务做成“配置项”,根据客户需求裁剪。这样能省下不少重复劳动。

3.3 服务ID(SID)与子功能:请求报文的结构

好了,现在我们知道了有哪些服务,也知道了哪些是必须的。那具体怎么用呢?这就得聊到SID和子功能了。

每个UDS服务都有一个唯一的ID,叫SID(Service IDentifier)。它占一个字节,比如22服务的SID就是0x22。诊断仪发请求时,第一个字节就是SID。

但有些服务,光有SID还不够。比如10服务(诊断会话控制),你得告诉ECU你想切换到哪个会话。是默认会话(01)?还是编程会话(02)?还是扩展会话(03)?这个额外的信息,就叫“子功能”(Sub-function)。

子功能也占一个字节,但它的最高位(bit 7)有特殊含义:

  • bit 7 = 0:表示这是一个“请求”,ECU执行完操作后需要发送正响应。
  • bit 7 = 1:表示这是一个“请求并抑制正响应”,ECU执行操作,但不需要回复正响应(除非有错误,错误响应还是要发的)。

举个例子,诊断仪想切换到编程会话:

请求报文:02 10 02
解释:
02    —— 数据长度(2个字节)
10    —— SID,诊断会话控制服务
02    —— 子功能,表示切换到编程会话(bit7=0,需要正响应)

ECU如果支持,会回复:

响应报文:06 50 02 00 32 01 F4
解释:
06    —— 数据长度
50    —— 正响应SID(请求SID + 0x40,即0x10 + 0x40 = 0x50)
02    —— 子功能回显
00 32 01 F4 —— 会话参数(比如P2超时时间、P2*超时时间等)

你看,正响应的SID就是请求SID加上0x40。这是UDS的一个固定规则,用来区分请求和响应。我曾经在调试一个项目时,发现ECU总是回复错误,查了半天,发现是响应SID写错了,写成了0x10而不是0x50。这种低级错误,排查起来真的很费时间。

避坑指南: 我曾经遇到过一个ECU,它对10服务的子功能bit7处理有bug。当诊断仪发送“抑制正响应”的请求时,ECU居然连负响应都不发了,直接死机。后来发现是代码里把“抑制正响应”理解成了“抑制所有响应”。记住:负响应(7F)永远不能抑制,这是协议明确规定的。

对于没有子功能的服务,比如22服务(读取数据),请求报文就直接是:

请求:22 F1 90
解释:
22    —— SID
F1 90 —— 数据标识符(DID),表示要读取ECU的某个特定数据,比如软件版本号

这种服务,就不需要子功能字节。所以你看,UDS的设计很灵活,有子功能的服务,通常都是那些需要“选择模式”或“选择操作类型”的。没有子功能的服务,则直接通过后面的参数来指定操作对象。

好了,这一章的内容就这些。总结一下:UDS服务按功能分为六大类,强制服务是地基,可选服务是装修。SID是服务的身份证,子功能是服务的操作模式。搞懂了这些,你就能看懂诊断仪和ECU之间在“聊什么”了。下一章,我们拿一个具体的服务——22服务(读取数据),来一次完整的实战演练。