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是“好搭档”,很多高级诊断功能都得先过安全访问这一关。