4、诊断会话控制(0x10):默认会话、扩展会话、编程会话的切换与特性
各位工程师朋友,咱们今天聊聊诊断会话控制。这个服务,服务ID是0x10,说白了就是ECU的“工作模式切换器”。你想想看,ECU不可能永远用一种姿态跟你对话——平时跑着的时候是一种状态,你要刷写固件的时候又是另一种状态。0x10服务就是干这个的。
我个人习惯把诊断会话比作“门禁卡”。默认会话是普通员工卡,能进大门但进不了核心机房;扩展会话是技术员卡,能进调试间;编程会话是管理员卡,能进服务器机房。嗯,这个比喻挺贴切。
4.1 三种会话的基本定义
UDS标准里定义了三种会话,但实际项目中我见过有些厂商自己加了第四种、第五种。不过咱们先把标准的三兄弟搞清楚:
| 会话类型 | 子功能值 | 典型用途 | 我见过的坑 |
|---|---|---|---|
| 默认会话 (Default Session) | 0x01 | 上电后的初始状态,日常通讯 | 有些ECU上电后不是默认会话,踩过雷 |
| 扩展会话 (Extended Session) | 0x03 | 诊断调试、读写参数、例程控制 | 扩展会话超时时间容易被忽略 |
| 编程会话 (Programming Session) | 0x02 | 刷写固件、Bootloader操作 | 编程会话中CAN总线负载率要控制好 |
核心要点:ECU上电后默认进入默认会话。只有通过0x10服务请求,才能切换到其他会话。而且,会话是有“超时”机制的——如果一段时间没收到任何诊断请求,ECU会自动跳回默认会话。
4.2 会话切换的请求与响应
咱们直接看报文格式。请求报文很简单:
请求:0x10 + 子功能值
例如:切换到扩展会话 → 发送 0x10 0x03
正响应报文长这样:
响应:0x50 + 子功能值 + P2_Server_max + P2*_Server_max
例如:0x50 0x03 0x00 0x32 0x00 0x1A
这里有个细节我要强调一下。正响应里带了两个时间参数:
- P2_Server_max:默认超时时间,单位是毫秒。比如0x0032就是50ms。
- P2*_Server_max:扩展超时时间,单位也是毫秒。比如0x001A就是26ms。
为什么会这样?因为不同会话下,ECU处理诊断请求的速度不一样。编程会话时ECU可能正忙着擦Flash,响应会慢一些,所以扩展超时时间会更长。我在项目中遇到过,有些测试人员没注意这个时间参数,用默认的50ms去等编程会话的响应,结果一直报超时——其实人家ECU需要200ms才能回应。
4.3 会话超时机制
这个机制特别重要,我建议你把它刻在脑子里。ECU内部有个定时器,叫S3Server。只要收到任何诊断请求(不限于0x10),这个定时器就会重置。如果定时器超时了,ECU就自动切回默认会话。
警告:千万不要以为只有0x10服务才能维持会话。任何诊断请求都能重置S3Server定时器。我曾经见过一个同事,在编程会话里只发了0x10请求,没发其他诊断报文,结果刷写到一半会话超时了,ECU跳回默认会话,刷写失败——那叫一个惨。
超时时间怎么算?标准里说:
- 默认会话:S3Server超时 = 5000ms(5秒)
- 扩展会话:S3Server超时 = 由ECU定义,通常5000ms
- 编程会话:S3Server超时 = 由ECU定义,通常也是5000ms
但实际项目中,我见过有些ECU把编程会话的超时设成了30秒。为什么?因为刷写过程中,擦除Flash那一步可能耗时很长,如果超时太短,ECU会频繁切回默认会话,导致刷写流程被打断。嗯,这里要注意,超时时间不是越长越好——太长了,万一通讯中断,ECU要等很久才能恢复。
4.4 会话切换的约束条件
不是所有会话之间都能随便切换的。我整理了一下:
| 当前会话 | 目标会话 | 是否允许 | 备注 |
|---|---|---|---|
| 默认 | 扩展 | 允许 | 最常用的切换 |
| 默认 | 编程 | 允许 | 需要安全访问(0x27) |
| 扩展 | 默认 | 允许 | 超时或主动切换 |
| 扩展 | 编程 | 允许 | 需要安全访问 |
| 编程 | 扩展 | 允许 | 刷写完成后常用 |
| 编程 | 默认 | 允许 | 刷写完成后的收尾 |
个人经验:从编程会话切回默认会话时,我建议先切到扩展会话,再切到默认会话。为什么?因为编程会话里ECU可能处于Bootloader模式,直接切回默认会话,有些ECU会重新初始化,导致一些诊断参数丢失。先切到扩展会话,让ECU有个缓冲,再切回默认,更稳妥。
4.5 实际项目中的避坑指南
做UDS诊断这么多年,我在0x10服务上栽过不少跟头。给你分享几个:
- 我曾经遇到过,ECU在编程会话里,CAN总线负载率飙到80%以上,结果S3Server定时器因为总线拥堵没及时重置,导致会话超时。解决方案:刷写时控制好报文发送间隔,别一股脑全发出去。
- 我记得有个项目,ECU的扩展会话超时时间设成了2000ms,但测试脚本里用的默认5000ms。结果每次跑测试都莫名其妙失败,查了两天才发现是超时时间不匹配。所以,一定要从正响应里解析P2和P2*参数,动态调整测试脚本的超时设置。
- 我个人习惯是在诊断工具里加一个“会话心跳”功能——每隔1秒发一个0x3E(Tester Present)请求,保持会话活跃。这样即使主流程卡住了,会话也不会超时。
4.6 负响应处理
如果ECU拒绝切换会话,会返回负响应。常见的否定码有:
| 否定码 | 含义 | 典型场景 |
|---|---|---|
| 0x12 | 子功能不支持 | ECU不支持编程会话 |
| 0x22 | 条件不满足 | 车速不为0时拒绝切换 |
| 0x33 | 安全访问未通过 | 没做解锁就切编程会话 |
| 0x78 | 请求正确但响应待定 | ECU正在处理,稍后再试 |
0x78这个否定码很有意思。它表示“我收到你的请求了,但还没准备好,你先等着”。我在项目中遇到过,ECU从默认会话切到编程会话时,需要先擦除一部分Flash,这个过程可能要几百毫秒。这时候ECU会先回一个0x78,等准备好了再回正响应。测试工具如果没处理好这个流程,就会误判为失败。
4.7 小结
0x10服务看似简单,但牵扯的东西不少。会话超时、安全访问、时间参数解析,每一个细节都可能成为坑。我建议你在做诊断测试时,先把会话切换的流程画出来,标清楚每个步骤的超时时间和前置条件。嗯,这样能省不少调试时间。
下一章咱们聊0x27安全访问服务——这个服务跟0x10是“好搭档”,很多高级诊断功能都得先过安全访问这一关。