3、会话控制服务(0x10):请求格式、肯定响应、否定响应、会话切换规则
好,咱们今天来聊聊UDS里最基础、也最常用的一个服务——0x10会话控制。说实话,这个服务看起来简单,但坑不少。我见过不少新手工程师,上来就调0x10,结果被否定响应搞得一头雾水。别急,咱们一步步拆开看。
3.1 请求格式:就三个字节的事儿
0x10服务的请求帧,结构非常清晰。说白了,就是告诉ECU:「嘿,我想切换到某个会话模式」。格式如下:
请求格式:
| 字节0 (SID) | 字节1 (子功能) |
| 0x10 | 会话类型 |
这里的子功能,就是你要切换的目标会话。UDS标准定义了三种默认会话:
| 子功能值 | 会话名称 | 说明 |
|---|---|---|
| 0x01 | 默认会话 (Default Session) | 上电后的初始状态,功能受限 |
| 0x02 | 编程会话 (Programming Session) | 用于刷写软件,权限较高 |
| 0x03 | 扩展会话 (Extended Session) | 用于诊断、标定等,比默认会话权限高 |
嗯,这里要注意,有些厂商会自定义会话,比如0x40、0x60之类的。但咱们做通用诊断开发,先把这三个标准会话吃透就行。
3.2 肯定响应:ECU说「好的,我切换了」
如果ECU同意切换,它会回一个肯定响应。格式也很简单:
肯定响应格式:
| 字节0 (响应SID) | 字节1 (子功能) |
| 0x50 | 会话类型 |
注意,响应SID是请求SID + 0x40。所以0x10的请求,肯定响应就是0x50。子功能字段会原样返回,告诉你当前切到了哪个会话。
举个例子,你发 10 03 请求切到扩展会话,ECU回 50 03,就表示切换成功。这时候你就可以开始做其他诊断操作了,比如读写数据、执行例程等。
我记得有一次,客户反馈说ECU切不到扩展会话。我抓了总线一看,ECU明明回了 50 03,但客户说还是不行。后来发现,是客户的上位机没正确处理肯定响应,以为没收到确认。所以啊,有时候问题不在ECU,而在工具链上。
3.3 否定响应:ECU说「不行,我拒绝」
ECU不是什么时候都听你的。如果它拒绝切换,就会回一个否定响应。格式如下:
否定响应格式:
| 字节0 (NRC SID) | 字节1 (SID) | 字节2 (NRC码) |
| 0x7F | 0x10 | 错误原因 |
常见的否定响应码(NRC)有这些:
| NRC码 | 含义 | 常见场景 |
|---|---|---|
| 0x12 | 子功能不支持 | 你发了个ECU不认识的会话类型 |
| 0x22 | 条件不满足 | 比如正在刷写时,不允许切到其他会话 |
| 0x13 | 消息长度错误 | 请求帧多了一个字节或少了一个字节 |
| 0x7F | 服务不支持 | ECU压根不支持0x10服务(极少见) |
3.4 会话切换规则:不是你想切就能切
会话切换不是随心所欲的。UDS标准定义了一套规则,我总结成三点:
- 只能从当前会话切到目标会话,不能跨会话跳转。比如从默认会话可以直接切到扩展会话,但不能从默认会话直接切到编程会话?嗯,其实标准允许直接切,但很多ECU会限制。具体看厂商实现。
- 会话有超时机制。默认会话通常没有超时,但扩展会话和编程会话一般有超时时间(比如5秒)。如果超时内没有收到任何诊断请求,ECU会自动切回默认会话。这是为了安全考虑,防止诊断会话一直占用总线。
- 某些服务只能在特定会话下执行。比如刷写相关的服务(0x34、0x36等)只能在编程会话下用。你如果在默认会话下发0x34,ECU会直接回否定响应。
我个人习惯,在写测试脚本时,会先发一个0x10 0x01切到默认会话,再切到目标会话。这样能确保ECU处于一个已知的初始状态,避免因为上一个测试残留的会话状态导致问题。
3.5 实战中的小技巧
最后,分享几个我在项目中积累的经验:
- 先确认ECU支持的会话列表。可以通过0x10服务的否定响应来试探,或者直接读ECU的配置参数。
- 注意会话超时。如果ECU在扩展会话下长时间没收到请求,它会自动切回默认会话。这时候你发其他服务,可能会收到0x7F或0x22。所以,建议在测试循环里定期发一个0x3E(Tester Present)来保持会话。
- 不要假设所有ECU行为一致。不同厂商、不同型号的ECU,对会话切换的实现可能有细微差别。比如有的ECU允许从编程会话切到扩展会话,有的则不允许。最好的办法是看对应的诊断规范文档。
好了,关于0x10会话控制服务,咱们就聊到这儿。下一节,我会讲讲安全访问服务(0x27),那可是个更刺激的话题。到时候见!