当诊断仪向ECU请求一段20字节的标定数据时,原始CAN帧的8字节限制迫使数据必须被拆分传输。这种看似简单的分片过程背后,隐藏着ISO 15765-2协议设计的精妙机制——首帧协商、流控同步、连续帧组装,每个环节都通过精确的定时参数确保数据可靠传递。本文将带您深入真实车载诊断通信的二进制世界,用Wireshark和CANoe捕获并解析这些隐藏在报文中的协议逻辑。
现代车载诊断通信如同精密运转的钟表,ISO 15765作为核心传动齿轮,连接着应用层的诊断服务与底层的CAN总线。不同于普通CAN通信的单层结构,诊断协议栈呈现出清晰的层级分化:
在Vector CANoe的Trace窗口里,一次完整的0x22读数据服务可能呈现这样的报文序列:
code复制1. 0x7E0 [8] 02 22 F1 90 00 00 00 00 // 诊断请求单帧
2. 0x7E8 [8] 10 14 62 F1 90 00 00 00 // ECU回复首帧
3. 0x7E0 [8] 30 00 00 00 00 00 00 00 // 诊断仪流控帧
4. 0x7E8 [8] 21 01 23 45 67 89 AB CD // ECU连续帧1
5. 0x7E8 [8] 22 EF 01 34 56 78 90 00 // ECU连续帧2
关键观察点:首帧的第二个字节0x14表示后续还有20字节数据(0x14=20),这与UDS响应数据长度直接相关
当ECU需要回复超过7字节的有效数据时(首帧数据域前两字节用于协议控制),会触发多帧传输流程。在Wireshark中识别首帧的特征:
数据总长度 = (Byte[0] & 0x0F) << 8 | Byte[1]例如捕获到报文10 14 62 F1 90...:
接收方通过流控帧控制数据传输节奏,其包含三个关键参数:
| 参数名 | 字节位置 | 取值说明 |
|---|---|---|
| FS | Byte[0]高4位 | 0x0-继续发送 0x1-等待 0x2-溢出 |
| BS | Byte[1] | 允许连续发送的帧数 |
| STmin | Byte[2] | 帧间最小时间间隔(ms) |
在CANoe CAPL中模拟流控响应:
c复制on message 0x7E0 // 诊断请求ID
{
if (this.byte(0) & 0xF0 == 0x10) // 检测首帧
{
byte fcFrame[8] = {0x30, 0x0A, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00};
// BS=10, STmin=20ms
output(fcFrame);
}
}
连续帧携带实际数据片段,其序列号循环计数机制确保数据有序重组:
重组算法示例:
python复制def reassemble_frames(frames):
data = bytearray()
for frame in frames:
if frame[0] & 0xF0 == 0x20: # 连续帧
sn = frame[0] & 0x0F
data += frame[1:] if sn != 0 else frame[2:] # 跳过PCI
return data
通过CANoe的IG模块故意延迟流控帧发送,可以直观观察N_Bs超时现象:
关键时间测量点:
code复制| 事件标记 | 时间戳(ms) | 差值 |
|-------------------|------------|--------|
| 诊断仪发送首帧 | 1000.0 | - |
| ECU收到首帧 | 1000.3 | 0.3 |
| ECU发送流控帧 | 1800.5 | 800.2 |
| 诊断仪重传首帧 | 2000.8 | 200.3 |
实验结论:N_Bs实际超时时间为1000ms,与协议规定完全一致
不同会话模式下的P2时间要求差异显著:
| 会话类型 | P2Server_max(ms) | P2*Server_max(ms) |
|---|---|---|
| 默认会话 | 50 | 5000 |
| 扩展会话 | 50 | 5000 |
| 编程会话 | 5000 | 5000 |
在AUTOSAR配置中调整这些参数:
xml复制<DIAG_CONFIG>
<P2_SERVER_MAX>50</P2_SERVER_MAX>
<P2_STAR_SERVER_MAX>5000</P2_STAR_SERVER_MAX>
<N_BS_TIMEOUT>1000</N_BS_TIMEOUT>
</DIAG_CONFIG>
通过PCAN-USB硬件断开ECU响应,观察诊断仪行为:
使用CANoe IG模块故意打乱连续帧顺序:
c复制on message 0x7E8
{
if (this.byte(0) & 0xF0 == 0x20) {
static int counter = 0;
if (++counter % 3 == 0) {
this.byte(0) = (this.byte(0) & 0xF0) | ((this.byte(0) + 1) & 0x0F); // 篡改SN
}
}
}
结果分析:
在实车测试中发现,某些ECU对N_Cr的处理存在差异:Bosch系ECU通常严格遵循100ms超时,而Continental产品则允许最大150ms的弹性时间。这种细节差异正是协议逆向工程的价值所在——只有通过实际报文捕获,才能建立准确的设备行为模型。