UDS协议基础:服务分类与核心诊断服务

UDS(统一诊断服务)是汽车电子诊断的通用语言。说白了,它就是ECU和诊断仪之间约定好的一套“对话规则”。你发一个请求,ECU回一个响应,就这么简单。但背后的设计,其实挺讲究的。

我个人习惯把UDS服务分成三类:诊断管理类、数据类和通信类。今天咱们重点聊四个最基础的服务:会话控制(0x10)、安全访问(0x27)和通信控制(0x28)。这几个服务,几乎每个诊断栈都会用到。

核心观点:UDS的每个服务都有固定的请求/响应格式。你只要掌握了这个格式,剩下的就是填参数。别被一堆SID吓到,其实逻辑很清晰。

UDS服务分类概览

UDS的服务标识符(SID)从0x00到0x3E,但常用的也就十几个。我按功能分了个类,你看这张表就明白了:

类别 SID范围 典型服务 用途
诊断管理类 0x10 - 0x3E 0x10(会话控制)、0x11(ECU复位)、0x27(安全访问) 控制诊断会话、安全认证、ECU复位等管理操作
数据类 0x22 - 0x2E 0x22(读取DID)、0x2E(写入DID)、0x23(读取内存) 读写ECU内部数据、参数、标定值
通信类 0x28 - 0x29 0x28(通信控制)、0x29(诊断故障码控制) 控制网络通信、DTC存储行为

你想想看,这三个类别其实对应了诊断的三个阶段:先建立会话(管理类),再验证身份(安全访问),最后读写数据或控制通信。顺序不能乱。

诊断会话控制(0x10)

0x10服务是诊断的“入口”。ECU上电后默认处于某个会话状态,诊断仪必须先发0x10请求,才能切换到目标会话。

会话类型主要有三种:

  • 默认会话(0x01):ECU上电后的初始状态。功能受限,只能做基本诊断。
  • 编程会话(0x02):用于刷写软件。我记得有一次项目,ECU在编程会话下才能解锁Flash写入权限。
  • 扩展诊断会话(0x03):用于高级诊断功能,比如读写标定数据、执行例程。我建议你在开发阶段多用这个会话,功能最全。

请求格式很简单:

请求:0x10 + 会话类型(1字节)
响应:0x50 + 会话类型 + P2_Server_max(2字节)+ P2*_Server_max(2字节)

嗯,这里要注意:响应里的P2_Server_max和P2*_Server_max,分别表示ECU处理请求的最大时间和扩展时间。如果超时了,诊断仪得重发请求。我在项目中遇到过,有些ECU的P2时间设得很短,导致诊断仪频繁超时。后来我们统一把P2_Server_max设为50ms,才稳定下来。

小技巧:切换会话时,ECU会退出当前会话并重置安全访问状态。所以,如果你需要安全访问,记得先切到目标会话,再发0x27请求。

安全访问(0x27)

0x27服务是用来“解锁”ECU的。为什么需要解锁?因为很多关键操作(比如刷写、标定)不能随便让任何人做。ECU会通过种子和密钥的校验,确认诊断仪是否合法。

流程分两步:

  1. 请求种子(0x27 + 子功能):诊断仪发请求,ECU返回一个随机种子(通常4字节)。
  2. 发送密钥(0x27 + 子功能+1):诊断仪用算法计算密钥,发给ECU。ECU比对后,返回成功或失败。

我曾经踩过一个坑:种子和密钥的算法,不同ECU可能不一样。有的用AES,有的用自定义异或。如果你在集成时发现安全访问总是失败,先检查算法是否匹配。

// 伪代码示例:安全访问流程
// 步骤1:请求种子
Request:  0x27 0x01
Response: 0x67 0x01 0x12 0x34 0x56 0x78  // 种子为0x12345678

// 步骤2:发送密钥(假设算法为种子+0x01020304)
Key = 0x12345678 + 0x01020304 = 0x1336597C
Request:  0x27 0x02 0x13 0x36 0x59 0x7C
Response: 0x67 0x02  // 成功
注意:安全访问失败次数过多,ECU可能会锁定诊断功能一段时间。我建议你在开发时,把失败重试次数设得小一点(比如3次),避免锁死。

通信控制(0x28)

0x28服务用来控制ECU的网络通信行为。说白了,就是让ECU“闭嘴”或者“说话”。这在刷写时特别有用——你不想ECU在刷写过程中还忙着发CAN报文吧?

子功能主要有:

  • 0x00:启用Rx和Tx——恢复正常通信。
  • 0x01:禁用Rx和Tx——完全静默。
  • 0x02:禁用Tx——只收不发。
  • 0x03:禁用Rx——只发不收。

我记得有一次,客户反馈刷写时总线负载过高。后来发现是ECU在编程会话下还在发送周期报文。我们用0x28服务把Tx禁掉,问题就解决了。

请求格式:

请求:0x28 + 子功能(1字节)+ 通信类型(1字节)
响应:0x68 + 子功能

通信类型通常用0x01表示“所有网络”,但也可以指定特定网络(比如CAN、LIN)。

知识结构图

下面这张图,把今天讲的四个服务的关系画出来了。你可以看到,会话控制是入口,安全访问是门槛,通信控制是工具。三者配合,才能完成完整的诊断流程。

UDS核心服务关系图 UDS核心服务关系图 0x10 会话控制 默认/编程/扩展 0x27 安全访问 种子→密钥校验 0x28 通信控制 启用/禁用Rx/Tx 0x22/0x2E 数据服务 读写DID 说明: 先通过0x10进入目标会话 → 再通过0x27解锁权限 → 最后用0x28控制通信或读写数据。

避坑指南

最后,分享几个我实际项目中遇到的坑:

  • 会话超时:ECU在非默认会话下,如果一段时间没收到诊断请求,会自动切回默认会话。我建议你把超时时间设得长一点(比如5秒),避免调试时频繁断连。
  • 安全访问锁死:有些ECU在安全访问失败5次后,会锁定30分钟。我曾经在测试时忘了重置计数器,结果等了大半个小时。嗯,后来我们加了个自动重置逻辑。
  • 通信控制影响其他节点:禁用Rx/Tx时,要确认不会影响其他ECU的通信。比如,你禁掉了网关的Tx,可能导致整个网络瘫痪。
我的建议:开发诊断栈时,先把0x10、0x27、0x28这三个服务调通。它们是最基础的,也是问题最多的。调通了它们,后面的数据服务就水到渠成了。