3、10服务详解:诊断会话控制请求与响应格式、子功能参数、P2与P2*定时
好,咱们今天来啃一块硬骨头——10服务(DiagnosticSessionControl)。说实话,这个服务在UDS协议里属于那种「看着简单,用起来全是坑」的类型。我最早接触它的时候,以为不就是切换个会话嘛,结果在项目联调时被P2定时坑得够呛。嗯,咱们今天就把它的里里外外掰扯清楚。
3.1 10服务到底是干嘛的?
10服务,说白了就是让ECU在不同工作模式之间切换。你想想看,ECU不可能永远处于同一个状态——平时跑着的时候是「正常模式」,刷写程序时需要「扩展模式」,做安全解锁时又得进「编程模式」。10服务就是干这个的。
我个人习惯把10服务比作ECU的「工作台切换」。就像你在工位上干活,有时候需要拧螺丝(正常模式),有时候需要接示波器(扩展模式),有时候还得把整个工作台翻过来修(编程模式)。不同的会话,决定了你能用哪些诊断服务。
核心要点:10服务不干别的,就负责告诉ECU:「嘿,我要换到XX模式了,你准备好。」
3.2 请求与响应格式
先看请求格式,这个很直观:
请求:02 10 [子功能]
| | |
| | └─ 子功能参数(01/02/03)
| └─ SID = 0x10
└─ 数据长度
响应格式分两种:肯定响应和否定响应。
肯定响应:
响应:03 50 [子功能] [P2_high] [P2_low]
| | | |
| | | └─ P2定时(高字节+低字节)
| | └─ 回显的子功能
| └─ 响应SID = 0x50
└─ 数据长度
这里有个细节我提醒一下:响应里会带P2定时值。很多工程师第一次看到这个会懵——「我发请求,ECU还告诉我它有多快?」没错,ECU会通过这个参数告诉你:「我处理这个会话下的请求,最快多久能给你答复。」
否定响应:
响应:03 7F 10 [NRC]
| | | |
| | | └─ 否定响应码
| | └─ 请求SID
| └─ 否定响应标识
└─ 数据长度
常见的NRC有:0x12(子功能不支持)、0x22(条件不满足)、0x78(请求正在处理)。
3.3 子功能参数详解
10服务定义了三个标准子功能,但实际项目中可能更多。我列个表,大家看得清楚:
| 子功能 | 名称 | 典型用途 | 我见过的坑 |
|---|---|---|---|
| 0x01 | 默认会话 | ECU上电后的初始状态 | 有些ECU退出其他会话后不会自动回默认,得手动切 |
| 0x02 | 编程会话 | 刷写Bootloader或应用程序 | 编程会话下通常禁止DTC存储,忘了恢复会出问题 |
| 0x03 | 扩展会话 | 需要更高权限的诊断操作 | 扩展会话的P2时间往往更长,别用默认值去算 |
我记得有一次,客户反馈说ECU在编程会话下无法响应某些请求。查了半天,发现是ECU在编程会话里把某些服务给禁用了。嗯,这其实符合规范——编程会话下,ECU只响应跟刷写相关的服务,其他的一律回NRC 0x11(服务不支持)。
我的建议:设计诊断功能时,一定要明确每个会话下允许哪些服务。别让测试工程师猜,写进诊断规范里最靠谱。
3.4 P2与P2*定时——最容易翻车的地方
好,重点来了。P2和P2*定时,我敢说80%的诊断联调问题都跟它俩有关。
P2定时:ECU处理一个请求并给出响应的最大等待时间。说白了,你发了个请求,ECU必须在P2时间内给你回话。如果没回,你就得认为出问题了。
P2*定时:当ECU需要更多时间处理时,它会先回一个NRC 0x78(请求正在处理),然后你就要用P2*定时来等它。P2*通常比P2长得多。
我画个时间线大家就明白了:
Tester ECU
| |
|---- 10 03 ------------>| 请求进入扩展会话
| | ECU开始处理
| | 需要更多时间...
|<--- 7F 10 78 ----------| 先回个「正在处理」
| | P2*定时开始计时
| | ECU继续处理...
|<--- 50 03 xx xx -------| 在P2*内给出最终响应
这里有个关键点:P2和P2*的值不是固定的。ECU在10服务的肯定响应里会告诉你当前会话下的P2值。我见过最离谱的情况是,某ECU在默认会话下P2是50ms,但切到扩展会话后P2变成了500ms。测试脚本没更新,结果一直超时。
避坑指南:我曾经在一个项目中,测试脚本写死了P2=100ms。结果ECU换了固件版本后,P2变成了150ms。所有测试用例全部失败。后来我学乖了——每次建立会话后,先解析响应里的P2值,动态更新超时时间。
关于P2和P2*的具体数值,ISO 14229-1里给了推荐值,但实际项目可以自定义。我一般这样设:
- 默认会话:P2 = 50ms,P2* = 2000ms
- 扩展会话:P2 = 200ms,P2* = 5000ms
- 编程会话:P2 = 500ms,P2* = 10000ms
为什么编程会话的P2*要设这么长?你想想看,刷写时ECU要擦除Flash、写入数据、校验完整性,这些操作动不动就几百毫秒甚至几秒。如果P2*设得太短,ECU还在擦Flash呢,你这边已经超时重发了,那不乱套了?
3.5 实际项目中的注意事项
最后,我分享几个实战经验:
- 会话切换的副作用:切换会话时,ECU可能会重置某些状态。比如从扩展会话切回默认会话,之前解锁的安全等级可能就失效了。设计测试用例时要注意这一点。
- 多客户端场景:如果总线上有多个Tester同时访问ECU,会话管理会变得复杂。有些ECU会拒绝非当前会话的请求,有些则会悄悄切换。嗯,这个得看具体实现。
- P2定时的精度:ECU给出的P2值是个参考,实际响应时间可能波动。我建议Tester端在P2基础上加20%的余量,别卡得太死。
- NRC 0x78的处理:收到0x78后,一定要用P2*定时重新等待,而不是继续用P2。我见过有人写代码时忘了更新定时器,结果P2*形同虚设。
好了,10服务的内容就这些。说白了,它就是个会话切换的「开关」,但P2和P2*定时才是真正的技术活。下一章咱们聊27服务——安全访问,那个更有意思。