第二讲:诊断服务概述——UDS协议简介、诊断服务分类、诊断会话控制

大家好,欢迎来到第二讲。

上一讲我们聊了Bootloader的整体架构,很多同学私信问我:“老师,诊断服务到底是个啥?跟Bootloader有啥关系?”

嗯,这个问题问得好。我当年刚入行时也困惑过——明明是个刷写程序的功能,怎么还要跟诊断协议扯上关系?后来踩了几个坑才明白:没有诊断服务,Bootloader就是个“瞎子”

一、UDS协议到底是什么?

UDS,全称Unified Diagnostic Services,统一诊断服务。说白了,它就是汽车电子世界里的一套“通用语言”。

你想想看,一辆车上几十个ECU,来自不同供应商,用的芯片、操作系统都不一样。如果没有统一的标准,A厂商的ECU说“我出故障了”,B厂商的ECU根本听不懂。那维修师傅不得疯掉?

UDS就是来解决这个问题的。它定义了一套标准化的“对话规则”——请求(Request)和响应(Response)的格式

核心要点:

  • UDS基于ISO 14229标准
  • 采用客户端-服务器模型(Client-Server)
  • 诊断仪(Tester)是客户端,ECU是服务器
  • 所有诊断请求和响应都遵循固定的报文格式

我在项目中遇到过最典型的情况:某次做Bootloader联调,供应商的刷写工具死活连不上我们的ECU。查了两天,最后发现是诊断请求的服务ID(SID)格式不对——对方把0x10写成了0x01。就这一个字节的差异,整个系统就“失语”了。

二、诊断服务分类——三大类,各有各的活

UDS协议里定义了26种诊断服务(从0x00到0x3E),但别被这个数字吓到。我习惯把它们分成三大类:

分类 服务ID范围 典型服务 作用
诊断管理类 0x10 - 0x3E 0x10(诊断会话控制)
0x11(ECU复位)
0x28(通信控制)
控制ECU的工作模式、状态切换
数据访问类 0x22 - 0x2E 0x22(读取数据)
0x2E(写入数据)
0x23(读取内存)
读写ECU内部的数据、参数、内存
传输功能类 0x34 - 0x36 0x34(请求下载)
0x36(传输数据)
0x37(请求退出传输)
实现大数据块的传输,比如刷写固件

为什么这么分?因为Bootloader主要用到的就是诊断管理类传输功能类。数据访问类更多是应用层在用,比如读取故障码、标定参数等。

我的经验:

做Bootloader开发时,你至少要把0x10、0x11、0x34、0x36、0x37这五个服务ID背下来。剩下的用到再查表,别给自己太大压力。

三、诊断会话控制——ECU的“工作模式”切换

这是今天最核心的内容。诊断会话控制,服务ID是0x10

为什么要有会话控制?

你想想看,ECU平时在车上正常跑着,控制发动机、刹车、气囊,这些都是安全关键功能。如果这时候诊断仪突然发个“写内存”的请求,ECU该不该执行?

当然不能!万一写坏了,车还在高速上跑着,那不是要命吗?

所以UDS定义了三种默认会话:

  • 默认会话(Default Session):0x01,ECU上电后的初始状态,只允许读取基本诊断信息
  • 编程会话(Programming Session):0x02,允许刷写固件、修改内存
  • 扩展诊断会话(Extended Diagnostic Session):0x03,允许读写标定参数、执行特殊功能

切换会话的流程很简单:

// 诊断仪发送请求
// 请求格式:0x10 + 目标会话ID
// 例如切换到编程会话:
请求:02 10 02
// 02表示后续有2个字节,10是服务ID,02是编程会话

// ECU正常响应:
响应:06 50 02 00 32 01 F4
// 50 = 10 + 0x40(响应标识)
// 02 = 编程会话
// 00 32 01 F4 = P2时间(50ms)和P2*时间(500ms)

注意:

我曾经在项目里犯过一个低级错误——编程会话切换成功后,忘记检查P2时间参数。结果刷写过程中,ECU因为超时自动退出了编程会话,导致刷写中断。那次差点把客户的样机刷成砖头。

所以,切换会话后一定要解析响应中的定时参数,这是很多新手容易忽略的细节。

四、会话切换的“潜规则”

嗯,这里要重点说一下。会话切换不是你想切就能切的,有几个关键点:

  1. 只能从默认会话切到其他会话。你不能直接从编程会话切到扩展会话,必须先回到默认会话。
  2. 会话有超时机制。ECU内部有个定时器,如果在P2*时间内没有收到任何诊断请求,ECU会自动回到默认会话。这是安全机制,防止诊断仪掉线后ECU一直处于“危险”状态。
  3. 某些服务只能在特定会话下执行。比如0x34请求下载,只能在编程会话下执行。你在默认会话下发0x34,ECU会直接回复NRC(否定响应码)0x7F。

我建议你在设计Bootloader时,把会话管理做成一个独立的状态机。这样代码清晰,也方便调试。

五、实战中的小技巧

最后分享几个我踩坑换来的经验:

  • 会话切换后,先发个0x3E(Tester Present)保持连接。0x3E是个“心跳包”,告诉ECU“我还活着,别超时”。我习惯每100ms发一次。
  • 编程会话下,禁用所有非必要的通信。比如CAN报文、网络管理报文,这些都会干扰刷写过程。用0x28服务关闭它们。
  • 记得处理NRC。ECU拒绝你的请求时,会回复否定响应码。常见的比如0x22(条件不满足)、0x33(安全访问拒绝)。别傻等,要解析NRC并做相应处理。

总结一下:

诊断服务是Bootloader的“入口”和“指挥棒”。UDS协议定义了通信的规则,诊断服务分类帮我们理清了功能边界,而会话控制则是整个诊断流程的“总开关”。

下一讲,我们会深入安全访问(0x27服务),这是Bootloader刷写前的最后一道防线。到时候我会分享一个我当年破解某供应商安全算法的故事,很有意思。

好了,今天就到这里。有问题欢迎在课程群里讨论,或者直接私信我。

课后思考:

如果你的ECU在编程会话下,突然收到一个0x11(ECU复位)请求,应该怎么处理?是立即复位,还是先完成当前传输?

答案下讲揭晓。