3. UDS服务详解

各位同学,今天我们正式进入UDS服务的核心地带。这五个服务,说白了就是诊断通信的"握手"和"门禁"。

我刚开始做诊断栈的时候,以为只要把协议栈跑通就行。后来才发现,这五个服务要是没处理好,后面的所有诊断流程都是空中楼阁。你想想看,ECU都不知道你现在处于什么会话模式,你怎么跟它谈读写数据?

核心认知:0x10、0x11、0x27、0x28、0x3E 这五个服务构成了诊断会话的"生命周期管理"。它们决定了ECU什么时候听你说话、听什么内容、以及如何保证通信安全。

诊断会话生命周期管理 默认会话 (0x01) 上电自动进入 非默认会话 编程/扩展会话 安全访问 (0x27) 解锁受保护功能 0x10 切换 0x27 解锁 通信控制 (0x28) 网络报文管理 测试仪在线 (0x3E) 保持会话活跃 ECU复位 (0x11) 软/硬/快速复位 可选控制 周期性发送 退出会话 💡 关键时序约束: • 0x3E 必须在 S3 超时时间内周期性发送(通常 2~5 秒) • 0x27 解锁失败超过次数限制后,ECU 会锁定安全访问一段时间

3.1 诊断会话控制(0x10)—— 会话的"切换开关"

0x10服务,说白了就是告诉ECU:"嘿,我要切换工作模式了。"

ECU上电后默认进入默认会话(Default Session)。在这个模式下,很多功能是被限制的。比如你想刷写固件,就必须先切换到编程会话(Programming Session)。

子功能 会话名称 典型用途
0x01 默认会话 上电默认,基础诊断服务可用
0x02 编程会话 Bootloader刷写、固件升级
0x03 扩展会话 高级诊断、标定、调试
0x04~0x3F OEM自定义 各主机厂私有会话

我的经验:有一次客户反馈ECU在编程会话下无法响应0x27服务。查了半天,发现是会话切换后没有重新初始化安全访问状态机。记住:每次会话切换,安全访问状态必须重置。这是很多新手容易踩的坑。

3.2 ECU复位(0x11)—— 让ECU"重启一下"

0x11服务,就是让ECU执行复位操作。它有三个常用的子功能:

  • 0x01 硬复位(Hard Reset):相当于断电重启,ECU完全重新初始化。
  • 0x02 钥匙下电复位(Key Off/On Reset):模拟钥匙下电再上电的过程。
  • 0x03 软复位(Soft Reset):仅复位应用层软件,不重新初始化硬件。
  • 0x04 快速复位(Fast Reset):某些OEM用于快速重启,跳过部分自检。

⚠️ 我曾经踩过的坑:在量产项目中,ECU收到0x11 0x03软复位后,立即发送了肯定响应,但实际复位动作有200ms延迟。测试仪在收到响应后立刻发送下一个请求,结果ECU还没复位完成,导致通信超时。解决方案:在复位响应后插入一个"静默期",让ECU有足够时间完成复位。

3.3 安全访问(0x27)—— 诊断的"门禁系统"

0x27服务,是UDS协议栈中最容易出bug的地方之一。它采用"挑战-应答"机制:

  1. 测试仪发送请求种子(Seed):0x27 + 子功能(奇数)
  2. ECU返回一个随机种子(Seed)
  3. 测试仪用算法计算密钥(Key),发送给ECU
  4. ECU验证Key是否正确,返回成功/失败
// 安全访问典型交互流程
// 步骤1:请求种子(子功能0x01 = 请求种子)
TX: 02 27 01
RX: 03 67 01 AA BB    // 种子 = 0xAABB

// 步骤2:发送密钥(子功能0x02 = 发送密钥)
TX: 04 27 02 11 22    // 密钥 = 0x1122
RX: 02 67 02          // 解锁成功!

// 如果密钥错误:
RX: 03 7F 27 35       // 否定响应:0x35 = 无效密钥
否定响应码 含义 常见原因
0x24 请求序列错误 没请求种子就直接发密钥
0x35 无效密钥 密钥计算错误
0x36 超过尝试次数 连续失败N次后锁定
0x37 需要时间延迟 防暴力破解机制

关键设计点:安全访问的种子生成算法和密钥计算算法,绝对不能明文存储在代码中。我见过有项目把算法直接写在.c文件里,结果被逆向工程轻松破解。建议使用查表法 + 动态混淆,或者把算法放在安全芯片中。

3.4 通信控制(0x28)—— 网络报文的"阀门"

0x28服务,用来控制ECU的网络通信行为。说白了,就是让ECU"闭嘴"或者"只听不说"。

子功能 控制类型 效果
0x00 使能Rx和Tx 恢复正常通信
0x01 使能Rx,禁用Tx ECU只收不发(静默模式)
0x02 禁用Rx,使能Tx ECU只发不收(很少用)
0x03 禁用Rx和Tx 完全静默

实际应用场景:在做CAN网络压力测试时,我们会用0x28 0x01让某个ECU进入静默模式,然后观察其他ECU是否还能正常通信。这招在排查网络干扰问题时特别好用。

3.5 测试仪在线(0x3E)—— 别让ECU"以为你走了"

0x3E服务,功能极其简单:告诉ECU"我还活着,别超时退出会话"。

但就是这么简单的服务,量产项目中出问题的概率反而最高。

⚠️ 我曾经踩过的坑:某项目在整车测试时,诊断会话总是莫名其妙退出。查了三天,发现是测试仪发送0x3E的周期是3秒,但ECU的S3超时时间设的是2.5秒。你想想看,每次0x3E还没到,ECU就已经超时退出了。解决方案:0x3E的发送周期必须小于S3超时时间的一半,一般建议1~2秒发一次。

0x3E还有一个容易被忽略的细节:它不改变当前会话的安全访问状态。也就是说,如果你已经通过0x27解锁了,发送0x3E不会导致锁定。但如果你在默认会话下发送0x3E,它也不会帮你解锁任何功能。

3.6 五个服务的协作关系

这五个服务不是孤立的。我画个简单的协作流程:

  1. ECU上电 → 进入默认会话
  2. 测试仪发送0x10 0x02 → 切换到编程会话
  3. 发送0x27请求种子/密钥 → 解锁安全访问
  4. 可选:发送0x28 0x01 → 让ECU静默,避免干扰刷写
  5. 周期性发送0x3E → 保持会话,防止超时退出
  6. 刷写完成后,发送0x11 0x01 → 复位ECU,回到默认会话

量产经验总结:

  • 会话切换后,必须重置安全访问状态机
  • 0x3E的发送周期 < S3超时时间 / 2
  • 安全访问的种子算法不要硬编码,用查表或动态生成
  • 0x28控制通信后,记得在退出会话前恢复使能
  • 0x11复位后,ECU需要足够的时间完成初始化再响应新请求