第三章 UDS服务分类:强制服务与可选服务、功能寻址与物理寻址、诊断会话控制

好,咱们继续往下走。第三章的内容,说白了就是UDS协议里最核心的骨架。你搞懂了这一章,后面看什么服务都不会觉得乱。我个人习惯把这一章叫做“UDS的交通规则”——什么车能上路,走哪条道,什么时候能跑,全在这儿了。

3.1 强制服务与可选服务:哪些是必须有的?

UDS协议里定义了一大堆服务,但并不是所有服务ECU都得支持。ISO 14229-1里把服务分成了两类:强制服务可选服务

强制服务,就是ECU必须实现的。你不实现,就不符合UDS规范。我在项目中遇到过一家供应商,他们做的BCM(车身控制器)居然不支持TesterPresent服务,结果产线刷写时总是超时断开。嗯,这就是典型的“该有的没有”。

强制服务其实不多,我列个表给你看:

服务ID 服务名称 说明
0x10 DiagnosticSessionControl 诊断会话控制,必须支持
0x11 ECUReset ECU复位,必须支持
0x27 SecurityAccess 安全访问,必须支持(如果ECU有安全锁)
0x28 CommunicationControl 通信控制,必须支持
0x3E TesterPresent 测试仪在线,必须支持
0x83 AccessTimingParameter 访问时序参数,必须支持
0x84 SecuredDataTransmission 安全数据传输,有条件必须
0x85 ControlDTCSetting 控制DTC设置,必须支持
0x86 ResponseOnEvent 事件响应,必须支持
0x87 LinkControl 链路控制,必须支持

重点来了:强制服务不是说你所有会话都得支持。比如0x10服务,你至少得支持默认会话(DefaultSession)和扩展会话(ExtendedSession)。编程会话(ProgrammingSession)可以没有,但默认会话必须有。

可选服务就多了去了。像0x22(ReadDataByIdentifier)、0x2E(WriteDataByIdentifier)、0x19(ReadDTCInformation)这些,都是可选的。但话说回来,虽然叫“可选”,实际项目中基本都会用。你想想看,一个ECU连DTC都读不了,那还诊断个啥?

我个人建议:做ECU开发时,先把强制服务列个清单,一条一条过。确保每个强制服务都实现了,再去做可选服务。我曾经吃过这个亏——先做了0x22和0x2E,结果发现0x3E没做,产线那边死活连不上。后来加班补的,教训深刻。

3.2 功能寻址与物理寻址:你是在跟谁说话?

这个知识点,很多新手容易搞混。我换个角度给你讲——你想想看,你在诊断仪上发一条指令,这条指令是发给一个ECU,还是发给一群ECU?

物理寻址,就是点对点通信。诊断仪发一条请求,只有一个ECU会响应。CAN总线上,物理寻址的CAN ID通常是唯一的。比如你发0x7DF,那是功能寻址;你发0x7E0,那就是物理寻址(假设ECU的物理请求ID是0x7E0)。

功能寻址,就是一对多通信。诊断仪发一条请求,总线上所有支持该功能的ECU都会响应。功能寻址的CAN ID通常是0x7DF(11位ID)或0x18DB33F1(29位ID)。

为什么要区分这两种?我给你讲个真实场景:

产线刷写时,需要同时给多个ECU发送编程会话请求。如果用物理寻址,你得一个一个发,效率极低。用功能寻址,一条0x10 02(请求编程会话)发出去,所有ECU同时响应,速度飞快。

但功能寻址也有坑。我记得有一次,我在测试台上发了一条功能寻址的0x11 01(硬复位),结果整个台架上的ECU全复位了。嗯,那场面,所有灯全灭,然后慢慢亮起来。从那以后,我发复位指令时都会再三确认是物理寻址还是功能寻址。

避坑指南:功能寻址的响应处理要特别小心。如果多个ECU同时响应,CAN总线可能会发生冲突。所以UDS规定:功能寻址的请求,ECU可以不应答(抑制正响应位SBS=1)。如果你需要所有ECU都应答,那就得做好冲突处理的准备。

我一般这样用:

  • 物理寻址:用于读写数据、执行例程、刷写单个ECU
  • 功能寻址:用于广播会话切换、全局复位、产线批量操作

你想想看,如果每次刷写都要一个一个ECU去切会话,那产线得慢成什么样?所以功能寻址在产线端用得特别多。

3.3 诊断会话控制:ECU的三种工作模式

诊断会话控制(0x10服务),是UDS里最基础的服务之一。它定义了ECU在不同诊断场景下的工作模式。

ISO 14229-1定义了三种标准会话:

会话ID 会话名称 子功能 典型用途
0x01 DefaultSession 默认会话 正常运行时,只支持少量诊断服务
0x02 ProgrammingSession 编程会话 刷写固件,支持0x34/0x36/0x37等
0x03 ExtendedDiagnosticSession 扩展诊断会话 读写数据、例程控制等高级诊断

为什么要有会话控制?说白了,就是安全考虑。ECU在正常运行时,不希望被随便读写数据。你想想看,如果谁都能在行车过程中改你的标定参数,那还得了?

所以UDS规定:默认会话下,只支持强制服务和少量安全服务。你想做更高级的操作,必须先切换到扩展会话或编程会话。

切换会话的流程很简单:

诊断仪发送:0x10 03(请求切换到扩展会话)
ECU响应:   0x50 03 00 32 01 F4(肯定响应,附带P2和P2*时间参数)

这里有个细节:ECU在响应0x10服务时,会返回两个时间参数——P2和P2*。P2是默认响应时间,P2*是扩展响应时间。这两个参数决定了诊断仪等待ECU响应的超时时间。

个人经验:我建议你在做ECU开发时,把P2时间设得宽松一点。比如默认会话设50ms,扩展会话设5000ms。为什么?因为扩展会话下可能要执行耗时操作(比如擦除Flash),时间太短容易超时。我曾经把P2*设成2000ms,结果刷写时总是超时重试,后来改成5000ms就好了。

会话切换还有一些规则:

  • 从默认会话可以切换到任何会话
  • 从扩展会话可以切换到默认会话或编程会话
  • 从编程会话只能切换到默认会话(不能直接切到扩展会话)
  • 切换会话时,ECU会重置一些状态(比如安全访问锁、DTC设置状态等)

嗯,这里要注意:会话切换时,ECU会清空安全访问的状态。也就是说,你切了会话,就得重新做安全解锁。这是安全设计,防止有人通过会话切换绕过安全验证。

最后说一个我踩过的坑:有一次我在做产线刷写工具,发现刷写过程中总是莫名其妙失败。查了半天,发现是TesterPresent(0x3E服务)没发。原来ECU在编程会话下有个会话超时时间(S3),如果超过S3时间没收到任何诊断请求,ECU会自动切回默认会话。而默认会话下不支持刷写服务,所以刷写就失败了。

从那以后,我写诊断工具时都会加一个定时器,每隔500ms发一次0x3E服务,保持会话活跃。这个习惯一直保留到现在。

好了,第三章的内容就这些。强制服务与可选服务让你知道ECU必须实现什么;功能寻址与物理寻址让你知道怎么跟ECU说话;诊断会话控制让你知道ECU在什么状态下能做什么事。这三块搞明白了,UDS的大门就算正式打开了。