3. 通信协议基础:UDS协议概述与核心服务

各位同学,今天我们来聊聊UDS协议。说实话,UDS(统一诊断服务)是ECU远程升级的“交通规则”。没有它,你的升级数据根本没法跟ECU正常沟通。

我最早接触UDS是在做T-Box项目的时候。那时候刚入行,觉得这协议又长又绕。后来踩了几个坑才明白——UDS的设计其实很巧妙。它把诊断和升级的“对话”标准化了,不管你是博世还是大陆的ECU,大家都能听懂彼此在说什么。

3.1 UDS协议概述

UDS全称是Unified Diagnostic Services,定义在ISO 14229标准里。它工作在OSI模型的应用层,底层通常走CAN总线(当然也能走以太网)。

说白了,UDS就是一套“请求-响应”的对话规则。客户端(比如诊断仪或OTA主控)发一个请求,服务器(ECU)回一个响应。每个请求和响应都有固定的格式。

这里有个关键点:UDS的每个服务都有一个唯一的SID(服务标识符)。比如0x10是诊断会话控制,0x27是安全访问。我习惯把SID想象成“指令编号”,ECU看到编号就知道你要干嘛。

核心概念:UDS的请求格式通常是 [SID] + [子功能] + [数据参数]。响应格式是 [SID+0x40] + [子功能] + [数据]。

举个例子:请求诊断会话控制(0x10),子功能是扩展会话(0x03),那么请求就是 10 03。如果ECU接受,响应就是 50 03。

3.2 诊断会话控制(0x10)

这个服务是UDS的“大门”。ECU上电后默认处于默认会话(Default Session),很多高级功能是锁着的。你必须先切换到正确的会话,才能做后续操作。

UDS定义了三种标准会话:

会话类型 子功能值 说明
默认会话 0x01 上电后的初始状态,功能受限
编程会话 0x02 用于刷写ECU,支持0x34/0x36等下载服务
扩展会话 0x03 用于诊断和标定,支持读写数据等

嗯,这里要注意:不同OEM可能会自定义会话。比如有些车厂会加一个“安全刷写会话”。但万变不离其宗,核心逻辑就是“先切换会话,再干活”。

我的经验:有一次我在做OTA升级时,发现ECU总是拒绝刷写请求。查了半天,原来是编程会话超时了。UDS规定,如果一段时间内没有活动,ECU会自动退回默认会话。所以升级过程中要定期发“保持活跃”的请求。

3.3 安全访问(0x27)

安全访问,说白了就是“对暗号”。你想对ECU做敏感操作(比如刷写固件),必须先通过安全验证。

流程是这样的:

  1. 客户端发请求种子(Seed):27 01
  2. ECU返回一串随机数(种子)
  3. 客户端用算法计算密钥(Key)
  4. 客户端发送密钥:27 02 [Key]
  5. ECU验证通过,解锁高级功能

我曾经在项目里遇到过一个问题:ECU返回的种子长度是4字节,但我们的算法只支持2字节。结果密钥总是算不对。后来发现是协议文档版本没对齐。所以啊,做安全访问一定要先确认种子长度和算法类型。

避坑指南:安全访问的算法通常是OEM保密的。有些ECU会限制尝试次数,比如连续3次失败就锁死30分钟。我在测试时就被锁过一次,只能干等着。所以开发阶段最好让ECU支持“解锁尝试次数重置”的功能。

3.4 通信控制(0x28)

这个服务用来控制ECU的通信行为。在OTA升级时特别有用——你可以让ECU暂时停止发送某些报文,避免干扰刷写过程。

常用的子功能:

  • 0x00:启用Rx和Tx(恢复通信)
  • 0x01:禁用Rx(停止接收)
  • 0x02:禁用Tx(停止发送)
  • 0x03:禁用Rx和Tx

你想想看,如果升级过程中ECU还在疯狂发CAN报文,万一刷写数据被冲掉了怎么办?所以升级前我通常会发一个28 03,让ECU闭嘴。升级完再发28 00恢复通信。

注意:通信控制会影响ECU的正常功能。比如你禁用了Tx,ECU就不会再发送心跳报文了。上层监控系统可能会误判ECU“掉线”。所以使用前要跟系统架构师确认好。

3.5 例程控制(0x31)

例程控制,你可以理解成“让ECU执行一段预设的程序”。比如擦除Flash、检查完整性、复位ECU等。

格式是:31 [子功能] [例程ID] [数据]

子功能有三种:

  • 0x01:启动例程
  • 0x02:停止例程
  • 0x03:请求例程结果

举个例子,刷写前要擦除Flash:

请求:31 01 FF 00  // 启动例程,例程ID=0xFF00(擦除Flash)
响应:71 01 FF 00  // 例程启动成功

我个人习惯把例程控制当成“ECU的API调用”。你不需要关心ECU内部怎么擦除Flash,只需要发一个31服务,它自己会搞定。这种抽象设计真的很棒。

我的建议:例程ID的定义一定要跟ECU供应商对齐。我曾经遇到过例程ID冲突的情况——两个不同模块用了同一个ID,结果一调用就死机。后来我们在设计阶段就建立了例程ID分配表,每个模块独占一段范围。

小结

好了,这一章我们讲了UDS的五个核心服务。0x10是进门,0x27是验证身份,0x28是控制通信,0x31是执行任务。它们组合起来,就构成了OTA升级的基础通信框架。

下一章我们会深入0x34(请求下载)和0x36(数据传输)——这才是真正传输固件数据的服务。到时候我会分享一个我踩过的“数据分包”大坑,保证让你印象深刻。