4、OBD诊断服务(一):模式$01与模式$02
各位同学,咱们今天正式进入OBD诊断服务的核心部分。说实话,模式$01和模式$02是你在实际开发中打交道最多的两个服务。我当年刚入行时,第一个项目就是做排放监测,天天跟这两个模式打交道。嗯,咱们一个一个来聊。
4.1 模式$01:请求当前动力总成数据
模式$01,说白了就是实时读取车辆当前的状态。你踩油门时发动机转速是多少?水温多少度?氧传感器电压多少?这些都能通过模式$01拿到。
它的PID(参数ID)范围是0x00到0xFF,但实际常用的也就那么几十个。我建议你先把下面这几个背下来,项目里天天用:
| PID | 名称 | 单位 | 公式 |
|---|---|---|---|
| 0x04 | 发动机负荷 | % | 100 * A / 255 |
| 0x05 | 冷却液温度 | °C | A - 40 |
| 0x0C | 发动机转速 | rpm | ((A * 256) + B) / 4 |
| 0x0D | 车速 | km/h | A |
| 0x10 | MAF空气流量 | g/s | ((A * 256) + B) / 100 |
你可能会问,为什么公式里都有A和B?因为CAN报文的数据域最多8个字节,每个PID返回的数据长度不一样。有的1个字节,有的2个字节。A是第一个字节,B是第二个字节,以此类推。
请求格式:
发送:02 01 PID CS
响应:04 41 PID 数据 CS
其中02表示数据长度,01是模式,PID是你想读的参数ID。
举个例子,我想读发动机转速(PID=0x0C)。发送的CAN报文是这样的:
// 请求发动机转速
CAN ID: 0x7DF
数据: 02 01 0C 00 00 00 00 00
// 正常响应
CAN ID: 0x7E8
数据: 04 41 0C 1A F8 00 00 00
// 解析:转速 = ((0x1A * 256) + 0xF8) / 4
// = ((26 * 256) + 248) / 4
// = (6656 + 248) / 4
// = 6904 / 4
// = 1726 rpm
我在项目中遇到过一个问题:有些ECU对模式$01的响应不是立即返回的,尤其是老款车型。你发完请求后,可能要等50ms甚至100ms才有响应。所以代码里一定要加超时处理,别傻等。
个人经验:我习惯在请求模式$01时,连续发3次请求,每次间隔20ms。因为有些ECU会丢帧,多发几次能提高成功率。但别发太快,否则ECU会认为你在攻击它。
4.2 模式$02:请求冻结帧数据
模式$02,说白了就是读取故障发生那一瞬间的快照。你想想看,发动机故障灯亮了,当时车速多少?转速多少?水温多少?这些数据都被ECU冻结保存下来了。
冻结帧的数据结构和模式$01几乎一模一样。唯一的区别是:模式$01读的是当前值,模式$02读的是历史值。
请求格式:
发送:02 02 PID CS
响应:04 42 PID 数据 CS
注意模式字节从01变成了02,响应字节从41变成了42。
举个例子,我想读故障发生时的发动机转速:
// 请求冻结帧的发动机转速
CAN ID: 0x7DF
数据: 02 02 0C 00 00 00 00 00
// 响应
CAN ID: 0x7E8
数据: 04 42 0C 15 30 00 00 00
// 解析:转速 = ((0x15 * 256) + 0x30) / 4
// = ((21 * 256) + 48) / 4
// = (5376 + 48) / 4
// = 5424 / 4
// = 1356 rpm
这里有个坑,我曾经踩过。模式$02不是所有PID都能读的。ECU只会保存和故障码相关的几个PID。比如P0300(多缸失火)的冻结帧,通常只保存转速、负荷、车速、冷却液温度这几个。你读PID 0x10(MAF空气流量)可能返回不支持。
注意:冻结帧数据是只读的,你没办法修改它。而且每次清除故障码后,冻结帧也会被清空。所以看到故障码后,第一时间读冻结帧,别等。
4.3 模式$01和模式$02的异同
咱们做个对比,一目了然:
| 对比项 | 模式$01 | 模式$02 |
|---|---|---|
| 数据来源 | 当前实时数据 | 故障发生时的快照 |
| 请求模式字节 | 0x01 | 0x02 |
| 响应模式字节 | 0x41 | 0x42 |
| PID支持范围 | 全部支持的PID | 仅故障相关的PID |
| 数据持久性 | 实时变化 | 清除故障码后消失 |
我个人习惯是:先读模式$03(故障码),如果有故障码,立刻读模式$02(冻结帧)。然后再读模式$01(当前数据),对比一下故障发生时的状态和现在的状态,这样能快速定位问题。
4.4 实战中的注意事项
嗯,这里要重点说一下。实际开发中,你可能会遇到以下几种情况:
- ECU无响应:发完请求后等了500ms还没响应。我建议重试3次,每次间隔100ms。如果还不行,就认为该ECU不支持。
- 响应数据异常:比如读车速返回了0xFF。这通常是ECU内部故障,或者CAN总线有干扰。可以多读几次取平均值。
- PID不支持:ECU会返回NRC(否定响应码)0x12(不支持该PID)。这时候别纠结,换个PID试试。
避坑指南:我曾经在某个项目里,发现模式$01读出来的水温一直是-40°C。查了半天,原来是ECU的CAN报文里,水温字节是0xFF(表示无效数据)。所以代码里一定要加数据有效性判断,别直接套公式。
好了,模式$01和模式$02就讲这么多。下节课咱们聊模式$03(读取故障码)和模式$04(清除故障码)。这两个在实际诊断中同样重要,尤其是做排放监测时,故障码的处理逻辑直接决定了你的系统能不能通过认证。
公众号:蓝海资料掘金营,微信deep3321