诊断服务实现(中):0x22、0x2E、0x2F 的配置与实现
好,我们接着聊诊断服务的实现。上一章我们把 0x10、0x11、0x19 这几个基础服务讲透了,今天要啃的这三块——0x22、0x2E、0x2F,说白了就是诊断世界里最常用的「读写控制」三板斧。
我个人习惯把这三个服务放在一起讲,因为它们在配置上有很多共通之处。你想想看,读取数据、写入数据、控制输入输出,本质上都是在跟 ECU 的内部数据打交道。只不过有的只读,有的可写,有的还要带点「副作用」。
0x22 读取数据标识符:最常用的诊断服务
0x22 服务,我敢说在量产项目中,它的调用频率能排进前三。不管是产线刷写后的版本校验,还是售后维修时的状态读取,都离不开它。
它的核心逻辑很简单:客户端发一个 DID(数据标识符),服务端把对应的数据值返回回去。但简单归简单,配置起来有几个坑我得提醒你。
DID 的配置要点
在 AUTOSAR 的配置工具里(比如 Vector 的 DaVinci Developer 或 EB 的 tresos),每个 DID 都需要绑定一个数据源。这个数据源可以是:
- 信号(Signal):直接从 SWC 的 Port 上读取
- 内存地址(Memory Address):直接读 RAM 或 Flash 的某个地址
- 组合 DID(Composite DID):把多个信号拼成一个 DID 返回
我在项目中遇到过一种情况:客户要求用一个 DID 返回整车的 VIN 码、ECU 硬件版本和软件版本。这时候用组合 DID 就特别合适。你只需要在配置里把三个信号按顺序排好,DCM 模块会自动帮你打包成响应报文。
关键配置参数:
DcmDspDidIdentifier:DID 的 ID,比如 0xF190DcmDspDidReadAccessAllowed:是否允许读取(有些 DID 只写不读)DcmDspDidReadDataLength:返回数据的长度,单位是字节DcmDspDidReadDataElementRef:绑定到具体的信号或内存地址
代码实现示例
嗯,这里要注意。虽然 AUTOSAR 的配置工具能生成大部分代码,但有些特殊 DID 还是得手写回调函数。比如读取一个需要实时计算的虚拟传感器值。
/* 0x22 读取 DID 的回调函数示例 */
Std_ReturnType Dcm_ReadDataByIdentifier(
Dcm_OpStatusType OpStatus,
Dcm_ServiceIdType ServiceId,
Dcm_DidType Did,
uint8 *DataBuffer,
uint16 *DataLength
)
{
(void)OpStatus;
(void)ServiceId;
switch (Did)
{
case 0xF190: /* 读取 ECU 软件版本 */
{
const uint8 swVersion[] = {0x01, 0x02, 0x03, 0x04};
memcpy(DataBuffer, swVersion, sizeof(swVersion));
*DataLength = sizeof(swVersion);
return E_OK;
}
case 0xF191: /* 读取实时车速(需要计算) */
{
uint16 vehicleSpeed = GetVehicleSpeed_kmh(); /* 从 CAN 信号计算 */
DataBuffer[0] = (uint8)(vehicleSpeed >> 8);
DataBuffer[1] = (uint8)(vehicleSpeed & 0xFF);
*DataLength = 2;
return E_OK;
}
default:
return E_NOT_OK; /* 不支持的 DID */
}
}
我的经验:回调函数里尽量别做耗时操作。我曾经见过一个同事在 0x22 回调里调用了 EEPROM 写入函数,结果诊断仪超时了。记住,0x22 是读取服务,响应时间通常要求在 50ms 以内。
0x2E 写入数据标识符:写操作要谨慎
0x2E 服务,说白了就是 0x22 的反向操作。客户端发一个 DID 和一段数据,服务端把它存到指定的位置。
这个服务在产线标定和售后配置修改时用得比较多。比如修改 VIN 码、配置车辆参数等。但我要强调一点:写入操作一定要做安全校验。
安全访问机制
大多数 OEM 都要求:在执行 0x2E 之前,必须先通过 0x27(安全访问)的解锁流程。否则,随便一个诊断仪就能改你的 ECU 参数,那还得了?
配置上,你需要把 DID 的写入权限和 Security Level 绑定起来:
| DID | 读取权限 | 写入权限 | 安全等级要求 |
|---|---|---|---|
| 0xF190(软件版本) | 始终允许 | 不允许 | N/A |
| 0xF191(VIN 码) | 始终允许 | 仅解锁后 | Security Level 1 |
| 0xF192(标定参数) | 始终允许 | 仅解锁后 | Security Level 2 |
避坑指南:我曾经在某个项目里,因为配置工具里忘了勾选「写入需要安全访问」的选项,结果导致产线上一个普通工位就能修改 ECU 的标定参数。还好在 DV 阶段发现了,不然量产就出大事了。所以每次配置完 0x2E,一定要检查安全访问的绑定关系。
写入回调的实现
/* 0x2E 写入 DID 的回调函数示例 */
Std_ReturnType Dcm_WriteDataByIdentifier(
Dcm_OpStatusType OpStatus,
Dcm_ServiceIdType ServiceId,
Dcm_DidType Did,
const uint8 *DataBuffer,
uint16 DataLength
)
{
(void)OpStatus;
(void)ServiceId;
switch (Did)
{
case 0xF191: /* 写入 VIN 码 */
{
if (DataLength != 17) /* VIN 码固定 17 字节 */
{
return E_NOT_OK;
}
/* 写入 NVM(非易失性存储器) */
if (Nvm_WriteBlock(VIN_BLOCK_ID, DataBuffer) != E_OK)
{
return E_NOT_OK;
}
return E_OK;
}
default:
return E_NOT_OK;
}
}
0x2F 输入输出控制:最灵活也最危险的服务
0x2F 服务,我个人觉得是这三个里面最有趣的。它允许诊断仪直接控制 ECU 的输入或输出信号。比如强制让某个执行器动作、模拟某个传感器的值。
这个服务在诊断测试和售后维修时特别有用。比如你要测试一个车窗电机,不需要真的去按开关,直接发一个 0x2F 请求就能让它升降。
控制模式
0x2F 支持三种控制模式:
- 0x00:返回控制状态——查询当前这个信号是否被诊断控制
- 0x01:复位为默认值——解除诊断控制,恢复 ECU 正常逻辑
- 0x02-0x7F:短时控制——强制信号为指定值,持续一段时间
嗯,这里要注意。0x2F 的控制是有时效性的。你想想看,如果诊断仪断开了连接,但 ECU 还一直保持强制控制状态,那车还怎么开?所以 AUTOSAR 规定,0x2F 的控制状态在 ignition off 或者 ECU 复位后会自动清除。
配置与实现
配置 0x2F 时,你需要为每个可控制的信号指定:
- 信号的数据类型(uint8、uint16、boolean 等)
- 控制的有效范围(比如某个执行器只能控制 0-100%)
- 超时时间(超过这个时间没有新的控制请求,自动复位)
/* 0x2F 输入输出控制回调示例 */
Std_ReturnType Dcm_InputOutputControlByIdentifier(
Dcm_OpStatusType OpStatus,
Dcm_ServiceIdType ServiceId,
Dcm_DidType Did,
const uint8 *DataBuffer,
uint16 DataLength
)
{
(void)OpStatus;
(void)ServiceId;
switch (Did)
{
case 0xF200: /* 控制左前车窗电机 */
{
uint8 controlMode = DataBuffer[0];
uint8 targetValue = DataBuffer[1];
if (controlMode == 0x01) /* 复位 */
{
WindowMotor_Reset(LEFT_FRONT);
}
else if (controlMode == 0x02) /* 短时控制 */
{
/* targetValue: 0=停止, 1=上升, 2=下降 */
WindowMotor_SetTarget(LEFT_FRONT, targetValue);
}
else
{
return E_NOT_OK;
}
return E_OK;
}
default:
return E_NOT_OK;
}
}
安全第一:0x2F 服务一定要加安全访问保护。我曾经在测试时,不小心用 0x2F 强制让一个风扇全速运转,结果测试台架上的温度传感器直接报警了。所以,对于可能造成物理伤害的控制(比如电机、风扇、阀门),建议使用 Security Level 3 或更高的等级。
三个服务的对比总结
最后,我用一张表帮你理清这三个服务的区别:
| 服务 | 方向 | 典型用途 | 安全要求 | 时效性 |
|---|---|---|---|---|
| 0x22 | 读取 | 版本信息、状态值、故障码 | 通常不需要 | 无 |
| 0x2E | 写入 | VIN 码、标定参数、配置 | 需要安全访问 | 永久存储 |
| 0x2F | 控制 | 执行器测试、传感器模拟 | 强烈建议 | 临时(复位后清除) |
好了,这一章的内容就到这。0x22、0x2E、0x2F 这三个服务,配置起来不算复杂,但细节很多。尤其是安全访问和超时处理,稍不注意就会出问题。下一章我们聊 0x14(清除诊断信息)和 0x19 的进阶用法,到时候见。