引子:一次失败的远程指导
2024年初,某维修站老师傅通过电话指导外地师徒诊断一辆无法上电的小鹏P7。
老师傅:“你用诊断仪读一下BMS的实时数据。”
师徒:“师傅,怎么读实时数据?”
老师傅:“选择数据流,然后点读取。”
师徒:“我点了,但是显示‘读取失败’。”
老师傅:“那你试试清除故障码。”
师徒:“也失败,显示‘超时’。”
老师傅意识到,师徒根本不知道诊断仪与车辆“对话”的底层逻辑。后来才发现,师徒的诊断仪没有正确进入扩展会话模式(Extended Session),所以无法读取实时数据。
这个案例揭示了一个核心问题:
大多数技师会“使用”诊断仪,但不理解诊断仪如何与车辆通信。这就像会打电话但不知道电话是如何接通的。
今天,我们将深入拆解UDS诊断协议(Unified Diagnostic Services,统一诊断服务),它是新能源汽车诊断的底层语言。
一、UDS协议是什么?
定义与标准
UDS(Unified Diagnostic Services,统一诊断服务) 是国际标准ISO 14229定义的诊断通信协议。
类比:
- 如果说CAN总线是“道路”,那么UDS就是“语言”
- 诊断仪通过CAN总线或以太网,用UDS语言与车辆的ECU“对话”
标准化的意义:
- 不同车企的ECU都遵循UDS协议
- 诊断仪只要支持UDS,就能诊断符合标准的车辆
- 但车企可以在标准之外添加“私有命令”(这就是为什么原厂诊断仪功能更强)
UDS通信的基础逻辑:请求-响应模式
UDS采用客户端-服务器模式:
- 客户端:诊断仪
- 服务器:车辆ECU(如BMS、MCU、VCU)
通信流程:
诊断仪发出请求报文 → ECU接收并处理 → ECU发回响应报文 → 诊断仪解析响应
关键特点:
- 一问一答:诊断仪发一条请求,ECU必须回复一条响应
- 有超时机制:如果ECU在规定时间内不响应,诊断仪会报错“超时”
- 有会话管理:不同的诊断功能需要在不同的“会话”中进行
二、UDS的核心概念:会话、服务、子功能
1. 会话(Session)
什么是会话?
想象你进入一个建筑物:
- 一楼大厅:任何人都可以进入,但只能看基本信息(默认会话)
- 二楼办公室:需要门卡权限,可以查看详细数据、执行测试(扩展会话)
- 三楼机房:需要更高权限,可以刷写软件、修改配置(编程会话)
UDS定义了三种核心会话模式:
会话1:默认会话(Default Session)
会话 ID:0x01
可用功能:
- 读取故障码(DTC)
- 清除故障码
- 读取基础身份信息(如VIN码、软件版本号)
限制:
- 不能读取实时数据流
- 不能执行器测试
- 不能刷写软件
类比:就像在银行大厅可以查询余额,但不能转账。
会话2:扩展会话(Extended Diagnostic Session)
会话 ID:0x03
可用功能:
- 默认会话的所有功能
- 读取实时数据流(如电池单体电压、电流、温度)
- 执行器测试(如强制关闭接触器、驱动电机)
- 读取冻结帧数据(故障发生时的环境数据快照)
进入方式:
诊断仪发送命令:10 03(其中10是服务ID“诊断会话控制”,03是扩展会话)
ECU响应:50 03 00 32 01 F4(表示成功进入扩展会话)
超时机制:
- 扩展会话有超时时间(通常5秒)
- 如果5秒内没有通信,ECU会自动退回默认会话
- 诊断仪需要定期发送“心跳包”保持会话(这就是开头案例中师徒的问题)
类比:就像在银行客户经理办公室,可以查询详细流水、进行转账操作。
会话3:编程会话(Programming Session)
会话 ID:0x02
可用功能:
- 下载和刷写ECU软件
- 修改标定数据
- 写入VIN码
安全限制:
- 通常需要安全访问验证(Security Access)
- 只有输入正确的“密钥”才能进入
- 不同车企的密钥算法不同(这就是为什么编程功能需要原厂授权)
类比:就像进入银行机房,需要最高权限和多重验证。
2. 服务(Service)
什么是服务?
服务就是诊断仪向ECU发出的“命令”,每个服务有一个字节的服务ID。
UDS定义了26种标准服务,以下是售后诊断最常用的服务:
服务列表
| 服务ID | 服务名称 | 功能 | 使用场景 |
|---|---|---|---|
| 0x10 | 诊断会话控制 | 切换会话模式 | 进入扩展会话/编程会话 |
| 0x11 | ECU重置 | 软重启/硬重启 | 刷写软件后重启 |
| 0x14 | 清除故障码 | 删除所有DTC | 维修后清除故障记录 |
| 0x19 | 读取DTC信息 | 读取故障码及相关数据 | 故障诊断 |
| 0x22 | 读取数据 | 读取实时数据流 | 监控电池电压、电流、温度 |
| 0x27 | 安全访问 | 身份验证 | 解锁编程功能 |
| 0x2E | 写入数据 | 修改配置参数 | 修改VIN码、标定数据 |
| 0x2F | I/O控制 | 控制输入/输出 | 测试继电器、电机 |
| 0x31 | 例程控制 | 执行特定测试程序 | 电池均衡、预充测试 |
| 0x34-0x37 | 数据传输 | 下载/上传数据 | 刷写ECU软件 |
| 0x3E | Tester Present | 保持会话活跃 | 防止会话超时 |
3. 子功能(Sub-function)
每个服务下面还有多个子功能,用于细化功能。
例子:服务0x19(读取DTC信息)的子功能:
| 子功能ID | 功能描述 | 应用 |
|---|---|---|
| 0x01 | 读取DTC的数量 | 快速了解有多少个故障 |
| 0x02 | 读取所有已确认DTC | 读取已点亮故障灯的故障码 |
| 0x03 | 读取所有待确认DTC | 发现潜在问题 |
| 0x04 | 读取DTC的快照记录 | 获取故障发生时的环境数据 |
| 0x06 | 读取扩展数据记录 | 获取故障发生次数、首次出现时间 |
三、UDS通信实例拆解
实例1:读取故障码
场景:技师用诊断仪读取BMS的故障码
Step 1:诊断仪发送请求
19 02 AF
解析:
- 19:服务ID = “读取DTC信息”
- 02:子功能 = “读取所有已确认DTC”
- AF:状态掩码 = 只读取已确认且当前存在的故障
Step 2:ECU响应
59 02 AF 03 C1 A0 31 5A F4 P0 A1 F3 48
解析:
- 59:正向响应(服务ID + 0x40)
- 02 AF:回显子功能和状态掩码
- 03:故障码数量 = 3个
- C1 A0 31 5A:故障码1(车辆私有格式)
- F4:故障状态字节(表示已确认、当前存在)
- P0 A1 F3:故障码2(OBD标准格式)
- 48:故障状态字节
故障码翻译:
- C1A0315A:电池包温度传感器5号线路开路
- P0A1F3:驱动电机控制模块性能故障
实例2:读取实时数据流
场景:技师想查看BMS的实时电流
Step 1:切换到扩展会话
请求:10 03
ECU响应:50 03 00 32 01 F4
解析:
- 10 03:请求进入扩展会话
- 50 03:确认进入扩展会话
- 00 32 01 F4:会话参数(如超时时间 = 5000ms)
Step 2:读取数据
请求:22 F4 54
ECU响应:62 F4 54 FF CE
解析:
- 22:服务ID = “读取数据”
- F4 54:数据标识符(DID,Data Identifier) = “BMS实时电流”
- 62 F4 54:正向响应,回显DID
- FF CE:数据值 = -50(十六进制转换为带符号整数)
数据解析:
- 原始数据:0xFFCE = -50(补码)
- 单位转换:-50 × 0.1A = -5.0A
- 含义:当前电池正在放电5A电流(负值表示放电)
Step 3:保持会话活跃
如果5秒内不再发送命令,ECU会退出扩展会话。为了持续监控,诊断仪需要每3秒发送:
3E 00
解析:
- 3E:服务ID = “Tester Present”(测试仪在线)
- 00:默认子功能
ECU响应:
7E 00
表示ECU收到心跳包,会话继续保持。
实例3:清除故障码
场景:维修后清除所有故障码
请求:14 FF FF FF
ECU响应:54
解析:
- 14:服务ID = “清除DTC”
- FF FF FF:故障码组掩码(全部清除)
- 54:正向响应,表示清除成功
注意:
清除故障码只是删除了记录,如果根本问题没解决,故障码会立即重新出现。
四、大家不知道的隐藏知识
1. 为什么有时诊断仪显示“负响应码”?
场景:技师尝试执行某个功能,诊断仪显示错误代码“0x7F”。
什么是负响应码?
当ECU无法执行请求时,会返回负响应码(Negative Response Code,NRC)。
负响应格式:
7F [Service ID] [NRC]
常见负响应码:
| NRC | 含义 | 原因 | 解决方法 |
|---|---|---|---|
| 0x11 | 服务不支持 | ECU不支持该服务 | 检查车型配置 |
| 0x12 | 子功能不支持 | 该服务下没有这个子功能 | 查阅技术手册 |
| 0x13 | 数据长度错误 | 请求报文长度不正确 | 检查命令格式 |
| 0x22 | 条件不满足 | 当前会话模式不允许 | 切换到扩展会话 |
| 0x31 | 请求超出范围 | 参数值超出允许范围 | 检查参数取值 |
| 0x33 | 安全访问被拒绝 | 未通过安全验证 | 执行安全访问流程 |
| 0x78 | 请求正确接收-响应待定 | ECU正在处理,请稍后 | 等待最终响应 |
实例:
技师在默认会话下尝试读取实时数据:
请求:22 F4 54
ECU响应:7F 22 22
解析:
- 7F:负响应
- 22:服务ID = “读取数据”
- 22:NRC = “条件不满足”
含义:当前在默认会话,不允许读取实时数据。
解决:必须先切换到扩展会话(发送 10 03)。
2. 为什么原厂诊断仪能看到更多数据?
秘密在于DID(数据标识符)
每个可读取的数据(如电池电压、电流、温度)都有一个唯一的DID编号。
标准化DID(通用诊断仪能访问):
- 0xF186:活动诊断会话
- 0xF187:车辆制造厂编码
- 0xF190:VIN码
- 0xF191:ECU软件版本号
私有DID(仅原厂诊断仪能访问):
- 0xF454:BMS实时电流
- 0xF455:BMS实时电压
- 0xF456-0xF4F5:电池包192个单体电压
- 0xF500:BMS SOC算法内部参数
- 0xF501:BMS允许最大充电功率
为什么通用诊断仪看不到?
因为通用诊断仪不知道这些私有DID的编号和数据格式。就像你不知道密码,就打不开保险柜。
原厂诊断仪的优势:
- 内置全部DID定义
- 知道每个DID的数据格式和单位
- 可以自动解析和显示
3. 为什么刷软件需要“安全访问”?
安全访问是一种挑战-响应验证机制。
流程:
Step 1:诊断仪请求种子(Seed)
请求:27 01
ECU响应:67 01 12 34 AB CD(返回一个随机种子)
Step 2:诊断仪用秘密算法计算密钥(Key)
Key = Algorithm(Seed, SecretCode)
例如:Key = 0x56 78 EF 01
Step 3:诊断仪发送密钥
请求:27 02 56 78 EF 01
ECU验证:用相同算法计算,对比结果
如果匹配:ECU响应 67 02(验证成功)
如果不匹配:ECU响应 7F 27 35(密钥错误)
为什么这样设计?
- 防止未授权刷写:只有拥有SecretCode的诊断仪才能刷写软件
- 防止竼听攻击:每次Seed都是随机的,即使竼听到一次的Key,也无法复用
- 控制维修授权:车企可以控制哪些维修企业有权刷写软件
破解难度:
不同车企的算法不同:
- 简单算法:XOR运算,可以被逆向工程
- 复杂算法:AES加密 + RSA签名,几乎无法破解
特斯拉的安全访问采用云端验证:
- 诊断仪必须连接特斯拉服务器
- 服务器验证诊断仪的授权状态
- 即使破解了算法,没有授权也无法使用
五、UDS诊断实战技巧
技巧1:理解会话超时机制
问题场景:
技师进入扩展会话后,读取了几个数据流,突然发现无法继续读取,显示“条件不满足”。
原因:
扩展会话超时,自动退回默认会话。
解决方案:
- 诊断仪软件应该自动每3秒发送一次 3E 00(Tester Present)
- 如果你的诊断仪没有这个功能,需要手动定期发送
技巧2:利用冻结帧数据进行故障分析
什么是冻结帧(Freeze Frame)?
当故障码被确认时,ECU会自动保存当时的环境数据快照,包括:
- 车速
- 电池SOC
- 电汁、电压
- 温度
- 行驶里程
如何读取?
使用服务 0x19 子功能 0x04:
请求:19 04 P0 A1 F3 48(读取故障码P0A1F3的冻结帧)
ECU响应:59 04 [Freeze Frame Data]
实战价值:
案例:某车辆出现“高压系统绝缘故障”,但客户说“我当时就正常行驶,什么也没做”。
读取冻结帧数据发现:
- 故障发生时车速:0 km/h
- 故障发生时环境温度:-15℃
- 故障发生时电池SOC:8%
结论:故障发生在冬天冷车低电量上电时,属于极端条件下的窞发性故障,建议监控后续表现。
技巧73:使用例程控制执行主动测试
服务0x31:例程控制可以执行预定义的测试程序。
常用例程:
| 例程ID | 功能 | 应用 |
|---|---|---|
| 0x0101 | 高压接触器闭合测试 | 验证预充电路功能 |
| 0x0102 | 电池均衡启动 | 主动启动均衡管 |