简介:面向汽车电子诊断初学者及ECU测试人员的UDS协议学习笔记,围绕ISO 14229标准梳理统一诊断服务的功能分类与请求响应逻辑,适合用于入门建立知识框架、项目开发前查阅服务定义。内容按诊断和通信管理、数据传输、已存储数据传输、输入输出控制、例程控制、上传下载等单元展开,涵盖0x10会话控制、0x11 ECU重置、0x27安全访问、0x22按标识符读数据、0x19读取DTC信息、0x31例程控制、0x34至0x37上传下载等常用服务,并说明“问—答”模式下正响应与负响应的判别方式,附录涉及NRC码汇总,便于定位常见错误。资源包共1个PDF文件,大小约10.49MB,单文件结构便于在电脑或平板上直接阅读与检索。目前已有1932人学习,可作为汽车诊断协议入门与日常查阅的参考材料。
1. UDS 是什么:把“修车”变成一场有规矩的问答
车开进维修站,师傅没有拆发动机,只是插上一根诊断线,屏幕上就跳出一行“某传感器信号异常”。这套看起来像玄学的操作,背后其实是一套叫 UDS 的对话规则。UDS 全称 Unified Diagnostic Services,中文一般叫统一诊断服务,是 ISO 14229 标准规定的一套汽车诊断协议。它做的事情很朴素:规定诊断仪和车上各个电子控制单元(ECU)之间,怎么问、怎么答、答错了怎么报。你可以把它理解成一本“问诊话术手册”——不管面对的是发动机、变速箱还是仪表,双方都按同一套话术来,才不会各说各话。搞懂 UDS,就等于拿到了看懂现代汽车“体检报告”的钥匙,也是很多诊断开发和测试工作的起点。
2. 为什么诊断要先“进对房间”:会话、复位与通信管理
2.1 0x10 诊断会话控制:所有命令的“入场券”
打个比方,一个 ECU 像一栋有很多房间的办公楼。Default Session 是大堂,谁都能进,但能做的事很有限;Extended Session 是会议室,能调的参数、能读的数据更多;Programming Session 是机房,刷写程序这类高危操作才允许在里面做。你要进哪个房间,得先跟前台报一声——这个“报一声”就是 0x10 服务,全称 DiagnosticSessionControl。
为什么非要分房间?因为有些服务在 Default Session 下压根不支持。比如安全访问、某些例程控制、上传下载,都要求你先切到扩展会话或编程会话。这就像你不能在大堂里直接去动配电箱,得先让人把你带到该去的地方。UDS 用会话把“低风险”和“高风险”操作隔开,既保护了 ECU,也让诊断流程有章可循。
请求的写法很直接:一个字节的服务 ID 加一个字节的子功能。比如10 03,10是服务号,03表示进入扩展会话。协议里已经定义好的子功能有01默认会话、02编程会话、03扩展会话,剩下的0x40到0x5F留给主机厂自定义。也就是说,你看到10 60这种请求,不要惊讶,那不是错,是厂家自己的会话档位。
正响应的格式是50加子功能回显,再加会话参数。这里有个判断正负响应的重要依据:正响应的服务 ID 等于请求服务 ID 加0x40。0x10的正响应就是0x50,0x22的正响应就是0x62。记住这个偏移量,看日志的时候能少走很多弯路。负响应则是固定的7F开头,后面跟请求服务 ID 和错误码,比如7F 10 22表示会话控制请求因为条件不满足被拒绝了。0x10常见的 NRC 有0x12(子功能不支持)、0x13(长度或格式不对)、0x22(条件不满足),每一个都对应不同的排查方向。
2.2 0x11、0x3E 与通信控制:让诊断“不断线”的几个服务
会话切过去只是开始,真正跑诊断的时候,还有几个管理类服务绕不开。第一个是 0x11 ECUReset,让 ECU 重启。请求里带一个复位类型,01是硬复位,02是钥匙关开复位,03是软复位。这个服务本身不复杂,但有一个细节容易翻车:复位成功之后,ECU 会回到 Default Session。如果你在自动化脚本里刚进扩展会话、做到一半,中间插了一个复位,后面的命令会齐刷刷报 NRC。血泪经验就是,凡是调用复位,后面必须重新走一遍会话切换,别指望它还留在原来的房间里。
第二个是 0x3E TesterPresent,诊断仪的心跳。ECU 在非默认会话下有一个超时机制,通常叫 S3 定时器,常见值是 5 秒。只要一段时间没收到任何请求,ECU 就自动退回 Default Session,把你之前的会话状态清掉。0x3E 的作用就是隔几秒喊一句“我还在”。请求写3E 00就行,正响应7E 00。做长流程测试的时候,没有这个心跳,脚本跑到一半会话掉了,现象就是莫名其妙的 NRC,很容易让人以为是安全访问出了问题。
第三个是 0x28 CommunicationControl,控制 ECU 收发正常通信报文。刷写之前经常要先把非诊断报文关掉,避免总线负载太高导致刷写失败。第四个是 0x85 ControlDTCSetting,打开或关闭故障码记录。做某些测试时不想让 ECU 记一堆假故障,就先把它关掉,测完再打开。这两个服务都属于“临时改变 ECU 行为”的操作,用完记得恢复,否则会留下后遗症。
2.3 一条请求的骨架:SID、子功能与数据
把上面这些服务拆开看,UDS 请求的基本结构其实就三段:服务 ID(SID,1 字节)、子功能(可选,1 字节)、数据参数(0 到多字节)。看几个例子就明白了。
22 F1 90 // 0x22 读数据,DID 是 F1 90(车架号) 62 F1 90 4C 58 ...// 正响应:62 是 0x22+0x40,后面跟 DID 和数据 7F 22 31 // 负响应:7F 固定,22 是请求服务,31 是 NRC 10 03 // 0x10 会话控制,子功能 03 进入扩展会话0x22那条请求里,22是 SID,后面的F1 90是数据参数,没有子功能。0x10那条里,03就是子功能。子功能在有些服务里还承担“奇偶区分”的作用,比如0x27安全访问,奇数表示请求种子,偶数表示发送密钥,这个后面单独讲。
负响应里的第三个字节 NRC 是排查问题的黑匣子。0x31是 requestOutOfRange,意思是请求的参数超出范围,常见于 DID 不存在;0x33是 securityAccessDenied,安全访问没解锁;0x22是 conditionsNotCorrect,当前会话或条件不满足;0x78是 responsePending,表示 ECU 还在处理,让你再等等。很多人看日志只看 SID 不看 NRC,结果一头雾水,其实答案全在最后那个字节里。
3. 读数据、看故障码:数据传输与已存储数据
3.1 0x22 按标识符读数据:DID 是数据的“身份证号”
诊断仪想知道某个具体数据,比如当前车速、软件版本、车架号,靠的就是 0x22 ReadDataByIdentifier。DID(Data Identifier)是两字节的编号,协议里规定了一批通用编号,比如F1 90是车架号,F1 86是软件版本号,F1 87是备件号。主机厂也会定义自己的 DID,用来读电池电压、电机温度这些私有数据。
为什么用编号而不是直接写名字?因为 ECU 的存储和带宽都很紧张,两字节的编号比一长串字符串短得多,解析也快。编号和含义的对应关系放在诊断数据库文件里,工具读数据库,人看含义,ECU 只认编号。这就像快递单号,你不需要知道单号是怎么生成的,只要能在系统里查到它对应哪件货就行。
请求的格式是22加 DID,正响应是62加 DID 加数据,负响应常见的有0x31(DID 不支持)和0x33(安全访问未解锁)。实际项目里,同一个 DID 在不同配置的车上可能长度不同,读之前最好先确认数据库版本,否则解析出来的数据会错位。这类问题不会报错,只会让你看到一串莫名其妙的值,属于典型的“数据能读到但看不懂”的踩坑场景。
3.2 0x19 读 DTC:故障码是车辆的“体检报告”
DTC(Diagnostic Trouble Code)就是常说的故障码。0x19 ReadDTCInformation 是读故障码服务的总入口,底下挂了一串子功能。最常用的是01按状态掩码读、02按状态掩码读支持的 DTC、04读快照、06读扩展数据、0A读所有支持的 DTC。
状态掩码是一个字节,每一位代表一种状态:testFailed表示当前测试失败,pendingDTC表示待定故障,confirmedDTC表示已经确认的故障,testNotCompletedSinceLastClear表示上次清码后还没测完。初学者最常犯的错误是只盯confirmedDTC,看到是 0 就以为车没问题。实际上pendingDTC往往是故障的早期信号,等它变成 confirmed 可能已经晚了。读故障码的时候把整个状态字节打出来,比只看一个“有没有故障”要有用得多。
0x19 04读快照也值得单独说。快照记录的是故障发生那一刻的环境数据,比如车速、水温、电压。修车的时候,光知道“氧传感器故障”不够,还得知道是在什么工况下出的问题,快照就是干这个用的。这部分数据在排查偶发故障时特别有价值。
3.3 0x2E 写数据与 0x14 清故障码:从读到改
0x22 是读,0x2E 是写,格式反过来:2E加 DID 加数据,正响应6E加 DID。写操作通常要先做 0x27 安全访问,不然直接吃0x33。常见的应用场景是写配置字、写 VIN、写标定参数。写之前一定要确认数据长度和字节序,写错了轻则配置不生效,重则 ECU 进入异常状态,这种操作没有后悔药,只能靠刷回备份。
0x14 ClearDiagnosticInformation 是清故障码,格式是14加三字节组号,FF FF FF表示清所有组。清完之后状态位归零,但要注意:有些故障是硬件问题引起的,清完马上又会重新置位。所以“清码”不是修车,只是把报告撕掉,问题还在那里。做测试的时候如果发现清完立刻又出现,说明故障条件一直满足,得去查根因,别在清码上反复折腾。
除了读写,协议里还有 0x2F 输入输出控制、0x31 例程控制、0x34 到 0x37 的上传下载。这些偏执行类,笔记里都有覆盖,但初学阶段先把“读”和“写”这两条线走通,再去碰刷写和例程,顺序会更顺。
4. 安全访问 0x27:种子和密钥的“对暗号”
4.1 为什么要有安全访问:给敏感操作上把锁
刷写程序、写配置、动标定,这些操作一旦被随便调用,轻则数据错乱,重则 ECU 变砖。0x27 SecurityAccess 就是给这类操作上的一把锁。它的逻辑不复杂:客户端证明自己有资格,ECU 才放行。这个“证明”不是报个密码那么简单,而是一套一次性的挑战应答。
协议文档里说得很清楚,下载或上传例程、读写特定内存位置,都可能需要安全访问。不加这层保护,错误的数据进去可能损坏电子设备,或者让车辆不满足排放和安全标准。所以别把 0x27 当成麻烦,它其实是保护机制。
4.2 种子与密钥:四步走完一次解锁
一次完整的解锁分四步:客户端请求种子,ECU 返回种子,客户端用种子算出密钥发回去,ECU 验证密钥。听起来像对暗号,实际也是。种子的作用是让每次的密钥都不一样,防止有人把某一组密钥写死重复使用。
请求种子的子功能是奇数,比如27 01;发送密钥的子功能是偶数,且等于种子请求子功能加一,比如27 02。这个奇偶对应关系是硬规定,27 01配27 02,27 03配27 04,以此类推。记混了就会出现“种子请求成功、密钥怎么发都失败”的情况。
下面是一段简化的 CAPL 风格伪代码,把流程串起来。具体工程里的函数名和配置项会不一样,但逻辑是一致的。
// 0x27 安全访问解锁流程(简化示意,具体配置随项目而定) diagRequest SeedReq; // 27 01 请求种子 diagRequest KeySend; // 27 02 发送密钥 byte seed[8]; byte key[8]; diagSendRequest(SeedReq); if (testWaitForDiagResponse(SeedReq, 1500) == 1) { // 响应前两字节是 SID 和子功能,从第 3 字节开始才是 seed for (int i = 0; i < elCount(seed); i++) { seed[i] = DiagGetRespPrimitiveByte(SeedReq, i + 2); } } // 用 seed 算出 key,算法由 ECU 供应商定义,这里不展开 diagGenerateKeyFromSeed(seed, elCount(seed), 1, variant, option, key, elCount(key), 8); // 把算好的 key 填进请求参数再发出去 diagSetParameterRaw(KeySend, "SecurityKey", key, elCount(key)); diagSendRequest(KeySend);代码里几个参数值得说明。elCount(seed)是种子数组的长度,常见是 4 字节或 8 字节,具体看项目。diagGenerateKeyFromSeed的第 3 个参数是安全级别,和第 4 个参数variant(ECU 名称)、第 5 个参数option(ECU 代号)一起决定用哪套算法。diagSetParameterRaw里的"SecurityKey"是参数名,必须和诊断数据库里的定义完全一致,写错了请求发出去的数据就不是你想要的,现象是密钥校验一直失败,但日志看起来“都发了”。
4.3 自动化里的坑:奇偶子功能与 NRC 35/36/37
安全访问有几个 NRC 特别值得记住。0x35是 invalidKey,密钥算错了;0x36是 exceedNumberOfAttempts,尝试次数超了;0x37是 requiredTimeDelayNotExpired,延时没到。这三个经常连着出现:第一次发错 key 报0x35,等一会儿再发错报0x36,再发报0x37。项目里常见的策略是错一次等 5 秒,错两次等更久,错三次锁一段时间。
做自动化测试的时候,这个惩罚机制很容易让脚本“莫名其妙卡住”。现象是前面几步都通过,到发密钥这步一直等不到响应。这时候别怀疑函数写错了,先看 NRC 是不是0x36或0x37,如果是,说明之前有失败的尝试把惩罚计时触发了,等够时间再重试才有用。另一个常见坑是种子和密钥的配对关系:27 01的种子只能用27 02去解,发到27 04上肯定不对。把这对关系记牢,能省掉大量排查时间。
5. 易混概念辨析:几组最容易混着用的词
5.1 0x27 安全访问与 0x29 认证:都是“验身份”,差别在哪
易混点:两个服务都跟“证明身份”有关,名字里都带安全意味,初学者容易以为 0x29 是 0x27 的新版本,随便用哪个都行。
为什么混:功能上有重叠,都是让客户端获得访问受限数据或服务的资格。而且 0x29 出现得晚,文档里又常和 0x27 放在一起讲。
怎么区分:0x27 是“种子—密钥”的挑战应答,轻量,靠 ECU 内部算法算 key,适合快速解锁;0x29 是完整的身份认证框架,支持基于 PKI 证书的交换,也支持不带证书的挑战应答,还能做单向或双向认证、建立会话密钥。通俗地说,0x27 像门禁刷卡,0x29 像一套带证件核验和双向确认的访客系统。项目里用哪个,取决于 ECU 的支持能力和安全等级要求,不是越新越好。
5.2 正响应、负响应与 NRC:三个容易搅在一起的说法
易混点:看日志时看到50、7F、31这些字节,分不清哪个是响应类型、哪个是错误码。
为什么混:负响应里同时出现了服务 ID 和 NRC,三个字节挨在一起,不熟悉结构就容易把请求服务 ID 当成错误码。
怎么区分:正响应的服务 ID 是请求 SID 加0x40,10对应50,22对应62;负响应固定以7F开头,第二个字节是原请求的服务 ID,第三个字节才是 NRC。记住“7F 后面第二个是服务、第三个是错误”,看日志就不会串。
5.3 DTC 与 DID:一个报故障,一个报数据
易混点:两个都是编号,都是两字节或三字节,初学时常把读 DTC 和读 DID 搞混。
为什么混:都走“发编号、回数据”的模式,工具界面上又都显示成码值。
怎么区分:DTC 是故障码,回答“哪里坏了”,通过 0x19 读、0x14 清;DID 是数据标识符,回答“现在是什么状态”,通过 0x22 读、0x2E 写。一个偏诊断结论,一个偏实时数据,用途完全不同。看到F1 90这种编号,先想它是 DID 还是 DTC,再决定用哪个服务。
5.4 Default Session 与其他会话:不是“模式”,是“权限档位”
易混点:把会话理解成界面上的“模式切换”,以为什么时候都能随便切。
为什么混:名字里带 Session,听起来像登录状态,容易低估它的约束力。
怎么区分:会话是权限档位,不同档位支持的服务集合不一样,而且有超时和复位清零机制。Default Session 是底座,一切从这开始;扩展会话和编程会话是往上加的权限,加了之后要靠 0x3E 维持,靠 0x11 打回原形。把它当成“进不同房间要不同门禁”,比当成“换个皮肤”准确得多。
6. 什么时候该用 UDS,什么时候别硬套
UDS 最适合的场景,是“按标准问、按标准答”的诊断交互。整车下线检测、售后读故障码、刷写前的条件检查、ECU 功能验证,这些都在它的舒适区里。它的价值在于统一:不同供应商的 ECU,只要遵循同一套服务定义,诊断仪就不用为每个零件写一套私有协议。对做诊断开发和测试的人来说,把 0x10、0x22、0x19、0x27 这几条主线吃透,大部分日常问题都能定位。
但它不是万能的。下面这张表把常见场景和适配度列了一下,判断边界时可以参考。
| 场景 | 适配度 | 说明 |
|---|---|---|
| 读故障码、清故障码 | 高 | 0x19 和 0x14 就是为此设计的 |
| 读软件版本、VIN 等标识 | 高 | 0x22 加标准 DID 即可 |
| 刷写程序 | 中高 | 需要 0x34 到 0x37 配合会话和安全访问,流程长、依赖多 |
| 实时控制执行器 | 中 | 0x2F 能做,但通常有更合适的标定通道 |
| 高频采样数据流 | 低 | 0x22 是请求应答模式,不适合高频轮询,得看 0x2A 这类周期服务 |
| 替代车载网络通信 | 低 | UDS 是诊断协议,不是通信协议,别拿它传业务数据 |
什么时候别硬套?第一种是把 UDS 当实时总线用。它的请求应答模型决定了每次读数据都要一来一回,采样率上不去,硬拿它做高频监控,只会把总线拖慢。第二种是没确认会话和安全状态就直接发服务。很多“命令发出去没反应”的问题,根子不在命令本身,而在当前会话不支持、或者安全访问没解锁。第三种是忽略 NRC 的语义,看到失败就重试。0x78是让你等,0x36是让你停,重试策略搞反了,越试越糟。
我自己刚开始接触诊断脚本的时候,就栽在会话超时上。脚本里有一段循环读数据,中间没加心跳,跑到第七八条的时候开始报0x7F 22 22,当时以为是 DID 写错了,查了半天数据库,最后才发现是 S3 定时器把会话踢回了默认态。从那以后我每次写长流程,都会在循环里强制走一遍心跳,并且在每条负响应后面打印 NRC,不再靠猜。希望这些经验能帮到你,少走一点弯路。
这份学习笔记把 ISO 14229 里的服务按功能单元梳理成册,从会话管理到安全访问、从读数据到刷写流程都有对应的章节和参数说明,适合放在手边当速查。需要完整资料的话,按页面提示获取即可。
本文还有配套的精品资源,点击获取