4. UDS协议在刷写中的应用:核心服务与机制
好,我们进入第四章。这一章可以说是整个刷写流程的“交通规则”——UDS协议。很多刚入行的工程师觉得UDS就是一堆服务ID,背下来就行了。其实不然。我个人习惯是把UDS看作一套“医生和病人的对话协议”,ECU是病人,诊断仪是医生,你想想看,医生要做什么?先问诊(读数据),再诊断(诊断故障),最后开刀(刷写)。
我在项目里见过太多人把34、36、37服务背得滚瓜烂熟,结果一上实车就报错——为什么?因为没搞懂会话状态和安全锁。这一章,我们就把这些核心服务拆开揉碎了讲清楚。
4.1 诊断会话控制(0x10服务)
ECU上电后默认处于默认会话(Default Session)。在这个状态下,很多刷写相关的服务是不开放的。你需要先切换到扩展会话(Extended Session)或编程会话(Programming Session)。
| 会话类型 | 子功能ID | 典型用途 | 我遇到的坑 |
|---|---|---|---|
| 默认会话 | 0x01 | 上电后默认,只允许基本诊断 | 直接发34服务会收到NRC 0x78(请求正确但当前会话不支持) |
| 扩展会话 | 0x03 | 读写参数、例程控制 | 有些ECU需要先切扩展才能解锁安全访问 |
| 编程会话 | 0x02 | 刷写专用,允许34/36/37等 | 切到编程会话后,很多非刷写服务会被禁用 |
4.2 安全访问机制(0x27服务)
刷写不是谁都能干的。安全访问机制就是ECU的“门锁”。你发一个seed请求,ECU给你一串随机数,你用算法算出key,再发回去。对上了,门就开了。
流程很简单:
- 发送 0x27 01(请求种子)
- ECU回复种子(4字节或8字节)
- 本地用算法计算key
- 发送 0x27 02(发送key)
- ECU验证通过,解锁
关键点: 安全算法通常是OEM自定义的。有的用AES,有的用CRC+异或,有的干脆就是个查表。我在一个项目里遇到过算法里藏了个时间因子——同一组seed在不同时间算出的key不一样,调试了三天才发现。
解锁后,ECU会保持解锁状态直到你切会话、下电或超时。超时时间一般是5秒,但有些ECU只有2秒。嗯,这里要注意:如果你刷写过程中耗时太长,需要定期发一些“保活”报文,比如0x3E 0x80(Tester Present)。
4.3 读取数据(0x22服务)与写入数据(0x2E服务)
这两个服务是“读写”搭档。22用来读,2E用来写。在刷写场景中,我们常用它们来:
- 读取ECU的软件版本号(DID 0xF190等)
- 读取VIN码
- 写入刷写标志位
- 写入配置信息
举个例子,读版本号:
请求:22 F1 90
响应:62 F1 90 01 02 03 04 // 版本号 01.02.03.04
写入配置:
请求:2E F1 90 01 02 03 04
响应:6E F1 90 01 02 03 04
4.4 例程控制(0x31服务)
31服务是用来执行一段“小程序”的。在刷写中,它通常用来:
- 擦除Flash(0xFF00)
- 检查编程条件(0xFF01)
- 复位ECU(0xFF02)
我个人习惯把31服务看作“ECU的API调用”。你传参数,它执行,返回结果。比如擦除Flash:
请求:31 01 FF 00 // 开始擦除
响应:71 01 FF 00 // 擦除成功
4.5 刷写核心三件套:34、36、37
这三个服务是刷写的核心。说白了就是:
- 34(请求下载): 告诉ECU我要写数据了,这是数据的起始地址和长度
- 36(传输数据): 一包一包地发数据
- 37(请求退出传输): 告诉ECU数据发完了,你校验一下
标准流程:
- 34 00 44 00 08 00 00 10 00 // 请求下载,地址0x00080000,长度0x1000
- ECU回复 74 00 44 00 20 // 同意下载,块大小0x20(32字节)
- 36 01 00 [32字节数据] // 第一块
- 36 02 00 [32字节数据] // 第二块
- ... 重复直到发完
- 37 00 // 请求退出
- ECU回复 77 00 // 传输完成
注意块大小: 34服务的响应中会返回一个“块大小”(Block Size)。这个值决定了你每包36服务能发多少字节。CAN 2.0一帧最多8字节,但UDS允许连续帧(CF),所以块大小可以大于8。我见过最大块大小是4096字节(用CAN FD)。但别贪心——块越大,出错重传的成本越高。
4.6 知识体系总览
下面这张图把本章的核心服务串起来了。你可以看到,刷写流程就是一条流水线:先切会话,再解锁,然后读写配置,执行例程,最后用34/36/37完成数据传输。
4.7 避坑指南
最后,我把自己这些年踩过的坑总结一下:
- 会话超时: 编程会话有超时时间,一般是5秒。如果你在刷写过程中不发任何报文,ECU会自动切回默认会话。我曾经在刷一个大文件时,中间计算校验花了3秒,结果ECU切回默认会话了,下一包36直接报错。
- 安全访问重试: 大多数ECU限制安全访问重试次数。连续输错3次key,ECU会锁定几分钟甚至几小时。所以,测试时一定要先确认算法正确。
- 34服务的地址对齐: 有些ECU要求起始地址必须按4字节或8字节对齐。不对齐的话,ECU会回复NRC 0x13(长度或格式错误)。
- 36服务的序列号: 36服务的第一个字节是序列号(0x01~0xFF),循环使用。但有些ECU要求序列号必须连续,不能跳号。我见过一个ECU,序列号从0x01跳到0x03就直接报错——中间缺了0x02都不行。