Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2.13 例行控制(0x31)——执行治疗

当你需要的不是改一个值,而是执行一整套操作

你坐在诊断仪面前,面前是一辆刹车踏板感觉偏软的轿车。你怀疑ABS液压单元内部有一个蓄压阀卡住了——但你不能拆开液压单元去看。你需要让ECU自己执行一套自动化检测流程:泵加压→保持压力→测量泄压速率→释放→回报结果。

这套流程有十几个步骤,每步都涉及ECU内部的多个寄存器操作——微控制器要切换阀体作动器、轮速传感器要监测每一个轮子的转速变化、压力传感器要连续采样并做峰值保持——整个过程持续数秒。

你不能用0x2F来做这件事——IO控制只能让你临时替代一个信号值,但它不能执行时间维度上展开的操作序列。你需要的不只是“把EGR阀开到30%“——你需要“给我执行ABS泵自检这整段程序”。

0x31 RoutineControl就是UDS对“程序化诊断操作“的回答。


为什么需要三阶段:start/stop/requestResults

你可能会觉得——不就一个“执行例程“的SID吗?为什么分三个子功能?

因为例程和简单的参数读写不同——它有两种属性:异步有持续时间

例程特征说明现实案例
异步启动后不会在当前MainFunction周期结束——需要多个ECU任务周期甚至多个驾驶循环才完成ADAS摄像头的在线标定——需要车以特定速度行驶在标线清晰的路面上持续数分钟
有中间状态执行过程中可以取中间信息和进度ABS自检——压力建立、保压泄漏检测、压力释放状态的百分比进度
可被中止诊断仪可能在执行期间改变主意——需要提前终止“紧急停止——不要继续这个例程——安全条件不足”

这三种属性映射到三个子功能:

子功能含义等价操作
0x01 startRoutine启动程序“开始执行RID=0x0201的操作”
0x02 stopRoutine终止程序“立即停止RID=0x0201的例程”
0x03 requestRoutineResults请求中间结果“RID=0x0201自检目前到什么地步了?”

核心洞察:0x31三阶段的子功能不是协议设计的审美偏好——它们是异步操作标准模型的直接翻译。启动一个不可预测时长的操作→随时询问它的状态→必要时中途终止——这三个动作覆盖了所有有状态操作的生命周期。


请求与响应格式

请求(startRoutine)

Byte 0: 0x31 (SID)
Byte 1: SubFunction (bit7=suppressPosRsp, bit6-0=0x01/0x02/0x03)
Byte 2-3: routineIdentifier (RID, 2字节大端序)
Byte 4..N: routineControlOptionRecord[] (可选输入参数)

RID(Routine Identifier)是一个2字节的数字——标识ECU上注册的诊断程序。ECU的配置表里存着RID→处理函数的映射。

正响应(startRoutine)

Byte 0: 0x71 (SID+0x40)
Byte 1: SubFunction回声
Byte 2-3: routineIdentifier回声
Byte 4..N: routineInfo[] / routineStatusRecord (输出)

routineInfo中包含routineStatus——一个字节编码执行状态:

routineStatus值含义
0x01例程执行完毕
0x02例程正在执行中
0x04用户手动终止
0x05例程执行失败——错误
0x06例程因安全策略被终止
0x07例程因依赖条件不满足被终止

完整的ABS自检用例——从启动到取结果

诊断仪 → ECU:
  0x31 0x01 0x02 0x01
  (startRoutine, RID=0x0201——ABS泵自检)

ECU → 诊断仪:
  0x71 0x01 0x02 0x01 0x01 0x00
  (正响应: routineStatus=0x01——已完成, 无错误)
  附加参数[0x00] = 自检通过码

---

如果例程执行需要时间——ECU先返回responsePending(0x78):

ECU → 诊断仪:
  0x7F 0x31 0x78
  (responsePending——还在跑, 诊断仪等待P2*时间)

... 几秒后...

ECU → 诊断仪:
  0x71 0x01 0x02 0x01 0x01 0x00 0x01 0x23 0x45...
  (最终响应: status=0x01完成, 附加泵压力曲线数据)

requestRoutineResults——取中间进度

如果例程运行时诊断仪想获取当前进度,它在任何时间都可以发:

诊断仪 → ECU:  0x31 0x03 0x02 0x01 (requestRoutineResults, RID=0x0201)
ECU → 诊断仪:
  0x71 0x03 0x02 0x01 0x02 0x3C
  (routineStatus=0x02还在跑, progressPercentage=0x3C=60%)

progressPercentage等中间结果字段由RID的配置表定义——ECU供应商在设计每个RID时规定了返回数据中哪些字节表示进度、哪些表示中间测量值。诊断仪通过ODX或诊断描述文件获知这些字段的布局。

核心洞察:requestRoutineResults是0x31对异步操作的“心跳窗口“——诊断仪不需要阻塞式等待例程执行完毕。它可以随时问“到哪了?“——ECU返回当前的进度数据和中间计算值。这在长时间运行的ADAS标定中尤其重要——你不想等10分钟再看结果。


stopRoutine——让程序提前终止

如果你发现某个例行程序在不安全的状态下运行,你需要强制终止它:

诊断仪 → ECU:  0x31 0x02 0x02 0x01 (stopRoutine, RID=0x0201)
ECU → 诊断仪:  0x71 0x02 0x02 0x01 0x04
  (routineStatus=0x04——用户手动终止)

为什么RoutineControl在默认会话不可用

0x31在标准层面并不限制会话——但大多数OEM将其配置为仅非默认会话(扩展会话0x03或编程会话0x02)可用。某些需要安全等级支持的例程还额外要求0x27解锁。这是因为例行程序可以是破坏性的——让ABS泵持续加压可能损坏液压密封——不能让任何插上OBD口的设备随便触发。如果你在默认会话下发0x31——ECU回复NRC 0x7F(serviceNotSupportedInActiveSession)。


和0x2F IO控制的根本区别

0x2F是即时操作——把当前信号值改成X——0ms延迟、马上生效、完成后立即交还。

0x31是异步操作——“开始一个任务”——没有预期完成时间、可以在过程中取进度、可以中途停止。

两者面对的两种不同的诊断场景:

  • “这个EGR阀动作有没有延迟?” → 0x2F——把它开30%,看看反馈传感器多久响应
  • “这个ABS泵有没有内部泄漏?” → 0x31——执行一整套自检程序,需要10秒、每个步骤都有压力和轮速的采集

本篇小结

  1. 0x31 RoutineControl是UDS的程序化诊断操作接口——用RID标识要执行的程序。
  2. 三种子功能(start/stop/requestResults)构成了异步操作的标准模型——启动、中止、查询进度。
  3. routineStatus字节返回了一个全面的执行状态——完成(0x01)、运行中(0x02)、用户终止(0x04)、失败(0x05)……
  4. requestRoutineResults是长时间运行程序的关键辅助——让诊断仪在程序执行期间取中间信息和进度。
  5. 0x31和0x2F的不同——前者异步、有状态、可中断的程序级操作;后者同步、瞬时的参数更换。

【下集预告】:0x31执行的是程序——0x2F是即时操作。你把这个信号值设为X——系统会怎么反应?就像医生按住病人的腹部问’按这里疼不疼’——你主动干扰,观察系统的被动反馈。