3. UDS协议核心
UDS(Unified Diagnostic Services,统一诊断服务)协议是ISO 14229标准定义的车载诊断应用层协议,它规定了诊断仪(Tester)与ECU(电子控制单元)之间进行诊断通信的会话规则、服务格式和响应机制。在DoIP(Diagnostic over Internet Protocol,基于IP网络的诊断)的传输基础上,UDS协议是诊断逻辑的真正载体。理解UDS协议的核心三要素——服务ID(SID)、子功能(Sub-function)和正负响应码(Positive/Negative Response Code),是进行ECU刷写、故障读取、数据标定和产线检测的必备基础。本章将逐一拆解这三个核心概念,并结合DoIP场景下的实际应用进行深度解析。
3.1 服务ID(SID)——诊断服务的“操作码”
3.1.1 核心原理:SID是UDS协议的命令字
SID(Service Identifier)是UDS请求帧的第一个字节,用于标识诊断仪希望ECU执行的服务类型。它类似于计算机指令集中的操作码(Opcode),决定了后续数据参数的解释方式。ISO 14229-1定义了从0x00到0x7E的标准服务ID范围,其中常用的服务包括:0x10(诊断会话控制)、0x22(按ID读取数据)、0x2E(按ID写入数据)、0x27(安全访问)、0x31(例程控制)、0x34(请求下载)、0x36(传输数据)、0x37(请求传输退出)、0x3E(测试仪在线)等。在DoIP场景下,SID被封装在DoIP消息的Payload中,通过TCP或UDP端口13400传输。
每个SID都有明确的请求格式和响应格式。例如,0x22服务的请求格式为:SID(0x22)+ DID(2字节数据标识符),响应格式为:SID+0x40(即0x62)+ DID + 数据。SID的设计遵循“请求-响应”的严格配对原则,ECU必须根据收到的SID类型执行对应的内部逻辑。
3.1.2 判断方法:SID的合法性与服务映射
诊断仪在发送请求前,需要确认目标ECU是否支持该SID。判断方法包括:
- 会话状态检查:某些SID仅在特定诊断会话(默认会话、编程会话、扩展会话)下可用。例如,0x34(请求下载)通常只在编程会话中允许。
- 功能寻址与物理寻址:物理寻址(Physical Addressing)时,SID必须被目标ECU支持;功能寻址(Functional Addressing)时,SID必须被多个ECU同时支持,且通常只允许无子功能或子功能为0x00的服务。
- 安全等级检查:涉及写入或刷写的服务(如0x2E、0x34、0x36)通常需要先通过0x27安全访问解锁。
ECU收到SID后,会先检查SID是否在自身支持的服务列表中。若SID无效或未定义,ECU将返回负响应码0x11(serviceNotSupported)。
3.1.3 案例拆解:0x22服务读取VIN码
假设诊断仪需要读取车辆的VIN码(车辆识别码),VIN码存储在ECU的0xF190数据标识符中。诊断仪发送的请求帧为:22 F1 90。ECU收到后,解析SID为0x22,确认支持该服务,且当前会话允许读取,则返回正响应:62 F1 90 4C 54 47 56 48 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35。其中0x62是正响应SID(0x22+0x40),0xF190是DID,后续字节为ASCII编码的VIN码。若ECU不支持0x22服务,则返回7F 22 11,表示服务不支持。
3.1.4 常见误区与总结
误区2:忽略会话状态直接发送服务请求。例如在默认会话下发送0x34请求下载,ECU会返回0x7F 0x34 0x7F(serviceNotSupportedInActiveSession)。
误区3:在DoIP中错误地使用UDP发送UDS请求。UDS请求通常使用TCP以保证可靠性,除非是广播类诊断(如功能寻址)才使用UDP。
3.2 子功能(Sub-function)——服务的“参数化开关”
3.2.1 核心原理:子功能扩展服务能力
子功能是请求帧的第二个字节(如果服务支持子功能),用于进一步细化服务的行为。子功能字节的最高位(Bit 7)具有特殊含义:当Bit 7为1时,表示抑制正响应(suppressPosRspMsg),即ECU执行服务后不发送正响应,只发送负响应(如果出错);当Bit 7为0时,ECU必须发送正响应。Bit 6~Bit 0用于表示具体的子功能值,范围从0x00到0x7F。
例如,0x10服务(诊断会话控制)的子功能包括:0x01(默认会话)、0x02(编程会话)、0x03(扩展会话)。0x31服务(例程控制)的子功能包括:0x01(启动例程)、0x02(停止例程)、0x03(查询例程结果)。子功能的设计使得一个SID可以承载多种操作模式,减少了SID的数量,提高了协议的可扩展性。
3.2.2 判断方法:子功能与SID的匹配规则
并非所有SID都支持子功能。例如,0x22(按ID读取数据)和0x2E(按ID写入数据)不支持子功能,请求帧中SID后直接跟DID。而0x10、0x27、0x31、0x3E等服务必须包含子功能字节。判断方法如下:
- 查阅ISO 14229-1标准或ECU的诊断规范,确认该SID是否支持子功能。
- 若支持,检查子功能值是否在ECU支持的范围内。例如,0x10服务的子功能0x04(扩展诊断会话)在某些ECU中可能不支持。
- 检查Bit 7的抑制正响应位。若置1,则ECU不发送正响应,但诊断仪仍需等待负响应(如果出错)或超时处理。
3.2.3 案例拆解:0x10服务切换会话
在DoIP刷写场景中,诊断仪需要将ECU从默认会话切换到编程会话。请求帧为:10 02(0x10是SID,0x02是编程会话子功能,Bit 7为0表示需要正响应)。ECU收到后,执行会话切换,返回正响应:50 02 00 32 01 F4。其中0x50是正响应SID(0x10+0x40),0x02是子功能回显,0x0032是P2(Server)定时器值(50ms),0x01F4是P2*(Server)定时器值(500ms)。若ECU不支持编程会话,则返回7F 10 12(subFunctionNotSupported)。
如果诊断仪希望抑制正响应,可以发送10 82(0x82 = 0x02 | 0x80)。此时ECU执行会话切换,但不发送正响应。诊断仪需要自行判断是否切换成功(例如通过后续的0x3E服务或读取会话状态DID来确认)。
3.2.4 常见误区与总结
误区:将子功能值与DID混淆。子功能是服务级别的参数,DID是数据级别的标识符,两者作用域不同。
3.3 正响应码与负响应码(NRC)——诊断结果的“状态机”
3.3.1 核心原理:正负响应的编码规则
UDS协议规定,ECU对每个诊断请求必须给出响应。正响应的SID为请求SID加上0x40,例如请求SID为0x22,正响应SID为0x62;请求SID为0x2E,正响应SID为0x6E。正响应中通常包含请求回显的数据或执行结果。负响应的SID固定为0x7F,后跟请求的SID和1字节的NRC(Negative Response Code)。NRC用于指示ECU拒绝请求的具体原因。
NRC的取值范围为0x00~0xFF,其中0x00是保留值,0x10~0x7F是标准定义的错误码,0x80~0xFF是制造商自定义的错误码。常见的NRC包括:0x10(generalReject)、0x11(serviceNotSupported)、0x12(subFunctionNotSupported)、0x13(incorrectMessageLengthOrInvalidFormat)、0x22(conditionsNotCorrect)、0x31(requestOutOfRange)、0x33(securityAccessDenied)、0x35(invalidKey)、0x36(exceedNumberOfAttempts)、0x37(requiredTimeDelayNotExpired)、0x7F(serviceNotSupportedInActiveSession)等。
3.3.2 判断方法:NRC的排查逻辑
当诊断仪收到负响应时,需要根据NRC快速定位问题。排查逻辑如下:
| NRC值 | 含义 | 常见触发场景 | 排查建议 |
|---|---|---|---|
| 0x11 | 服务不支持 | SID未定义或ECU未实现 | 检查ECU诊断规范,确认SID是否有效 |
| 0x12 | 子功能不支持 | 子功能值超出范围 | 检查子功能定义,确认是否支持该模式 |
| 0x13 | 报文长度或格式错误 | 请求帧长度与SID要求不符 | 核对请求帧字节数,检查DID长度 |
| 0x22 | 条件不满足 | 会话状态、安全等级、电压条件等不满足 | 检查当前会话、安全解锁状态、ECU运行条件 |
| 0x31 | 请求超出范围 | DID不存在、数据值超出上下限 | 检查DID范围和数据有效性 |
| 0x33 | 安全访问被拒绝 | 未解锁或密钥错误 | 先执行0x27安全访问流程 |
| 0x7F | 当前会话不支持 | 在默认会话下发送编程会话专属服务 | 先切换会话再发送请求 |
3.3.3 案例拆解:0x2E写入DID失败排查
场景:诊断仪尝试通过0x2E服务向ECU写入DID 0xF190(VIN码),请求帧为2E F1 90 4C 54 47 56 48 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35。ECU返回负响应7F 2E 22(conditionsNotCorrect)。
分析过程:
- 检查当前会话:ECU处于默认会话(0x01),而0x2E写入服务通常需要在扩展会话(0x03)或编程会话(0x02)下执行。
- 检查安全等级:0x2E写入操作需要安全访问解锁(0x27服务),当前ECU处于锁定状态。
- 检查DID属性:0xF190在ECU中定义为只读DID,不允许写入。
解决步骤:先发送10 03切换到扩展会话,再执行27 01安全访问解锁(发送种子和密钥),最后重新发送0x2E写入请求。若仍失败,检查写入数据的长度和格式是否符合DID定义。
3.3.4 常见误区与总结
误区:将0x7F误认为是负响应SID。0x7F是负响应的固定SID,真正的错误原因在NRC字节中。例如
7F 22 31表示0x22服务返回0x31错误(请求超出范围),而不是0x7F服务。
3.4 三要素协同:构建完整的诊断请求-响应链路
3.4.1 核心原理:SID、子功能、NRC的联动关系
在实际诊断中,SID、子功能和NRC不是孤立的。SID决定了服务的类型,子功能决定了服务的行为模式,NRC则反映了ECU对请求的接受程度。三者共同构成了UDS协议的状态机。例如,0x31服务(例程控制)的子功能0x01(启动例程)在ECU执行过程中,如果例程内部参数错误,ECU可能返回0x31(requestOutOfRange);如果例程需要安全解锁,则返回0x33(securityAccessDenied)。诊断仪必须根据NRC动态调整请求策略。
3.4.2 操作流程:诊断请求的完整处理流程
- 构建请求帧:根据诊断需求,确定SID、子功能(如有)和数据参数。
- 封装DoIP消息:将UDS请求放入DoIP Payload中,添加DoIP头部(版本、类型、长度等)。
- 发送并等待响应:通过TCP发送,等待ECU的响应帧。若超时(P2/P2*定时器),则重试或报错。
- 解析响应帧:检查响应SID。若为SID+0x40,则处理正响应数据;若为0x7F,则解析NRC并执行对应处理。
- 状态更新:根据响应结果更新诊断会话状态、安全等级、故障码等。
3.4.3 实战场景:DoIP刷写流程中的三要素应用
在OTA(Over-The-Air)刷写场景中,诊断仪需要依次执行:0x10(切换到编程会话)→ 0x27(安全访问解锁)→ 0x31(擦除Flash例程)→ 0x34(请求下载)→ 0x36(传输数据)→ 0x37(请求传输退出)→ 0x11(ECU复位)。每一步都可能返回不同的NRC。例如,0x34请求下载时,若内存地址超出范围,ECU返回0x31;若安全等级不足,返回0x33;若当前会话不是编程会话,返回0x7F。诊断仪需要根据NRC决定是重试、切换会话还是终止刷写。
3.4.4 常见误区与总结
总结:掌握SID、子功能和NRC的解析,是UDS协议栈开发的第一步。建议在实际项目中,建立一张“SID-子功能-NRC”映射表,并针对每个服务编写单元测试用例,覆盖正响应和常见负响应路径。