第三章 传输层 —— CAN与DoIP的双车道
3.1 ISO 15765-2——CAN上的UDS
你有一个8字节的信封,要寄一封1000字的信
CAN总线的数据帧的有效载荷——正好8个字节。你的UDS诊断请求0x22 0xF1 0x90只用3字节,那就一个CAN帧搞定。但如果你的UDS请求长达几十字节——比如你要读取DID的数据记录要多处并传、或者上传/下载大批数据——8字节远不够用。
工程师对这个问题的回答叫做ISO 15765-2——它是CAN总线上传输层的核心标准,负责把任意长度的诊断报文编码成一系列8字节CAN帧,再从接收端把它们粘合复原。
四种帧类型——从单帧到位流
ISO 15765-2的数据帧分为四类——每一个CAN帧的一个特殊字节(PCI——Protocol Control Information,帧头)解码出是哪一类:
| 帧类型 | 缩写 | PCI字节格式 | 用途 |
|---|---|---|---|
| Single Frame | SF | 0 0xxxxxxx (bit7=0) | 单帧——整个请求<=7字节数据 |
| First Frame | FF | 1 0001xxxx xxxxxxxx (高4位=1, 低12位=总长度) | 巨帧的第一帧——宣告“接下来共有NN字节“ |
| Consecutive Frame | CF | 2 xxxxxxxx (高4位=2) | 巨帧的后续分段——携带SN(序列号) |
| Flow Control | FC | 3 x xxxxxxxx (高4位=3) | 接收端反馈——“继续发“或“等等“或“溢出” |
核心洞察:ISO 15765-2不打算在CAN层面做任何状态复杂的可靠性保证——它只解决一个问题:在8字节信封里切分消息并在接收端组合。用四个帧类型的最小集实现可靠、有效的流控——不引入TCP的复杂状态机。这就是“适合CAN总线的分段协议“能长到今天的根因。
单帧(SF)——短消息一帧搞定
CAN ID DLC=8 (表示8字节数据)
┌──────┬─────────────────────────────────────────────────┐
│ PCI │ UDS data (最多7字节) │
│ Byte0│ Byte1..Byte7 │
└──────┴─────────────────────────────────────────────────┘
PCI Byte 0:
bit7 = 0 (SF标志)
bit6-4 = 000 (保留)
bit3-0 = SF_DL (数据长度, 0~7)
UDS请求0x10 0x03可以在一个SF帧中完成:PCI=0x02(数据长2字节), 数据=0x10 0x03, 其余字节任意→CAN帧={0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}。
巨帧的分段魔法——FF → CF → CF → …
一个UDS请求可能有1000字节长度。这是ISO 15765-2的主场。
First Frame (FF)——第一帧宣告总长度:
PCI:
Byte 0: 高4位=1, 低4位=总长度的高4位 (bit0-3)
Byte 1: 总长度的低8位 (bit4-11)
→ 12位编码长度: 0~4095字节
数据:PCI字节后的6字节是第一段实际数据
Flow Control (FC)——ECU收到FF后必须回复的决定:
PCI:
Byte 0: 高4位=3 (FC)
bit3-0: Flow Status
0 = CTS (ClearToSend) —— 继续发
1 = WT (Wait) —— 等一下
2 = OVFLW (Overflow) —— 缓冲区满了,停止
Byte 1: Block Size (BS) —— 多少个CF帧之后ECU回复下一个FC
0 = 无限——不需要中间FC, 一直发到完
Byte 2: Separation Time Min (STmin) —— 两个CF帧间最小间隔
0x00-0x7F: 微秒(us)
0xF1-0xF9: 100us~900us
其他: 毫秒
工程典型值:BS=0(无限,发送端连续发完所有CF帧,无需中间FC确认)、STmin=5~10ms(两次CF帧之间的最小间隔,给ECU留足缓冲时间)。多数ECU的FC配置为
0x30 0x00 0x05=CTS, BS=0, STmin=5ms。
Consecutive Frame (CF)——数据的分段载体(每帧1字节PCI + 7字节数据):
PCI:
Byte 0: 高4位=2 (CF)
bit3-0: Sequence Number (SN) —— 4位, 从1开始, 循环1~15
SN序列号——丢失检测
当发送多个CF帧时,每个CF的SN从1递增。序列1→2→3→…→15→0→1循环。如果ECU收到SN=5, 但预期SN=4——说明之前的CF帧被CAN碰撞丢失。
ECU回复另一个FC(CTS)——请求从SN=0x04重新开始传输整个块。
核心洞察:FC机制是ISO 15765-2最精巧的部分——它把流控决策从发送端交到接收端。ECU根据自己硬件的缓冲区和CPU负载发送FC反馈——CTS=来、WT=慢点、OVFLW=停。发送端诊断仪不主动判断ECU的状态——ECU在每一个FC中告诉诊断仪怎么做。
完整的巨帧传输范例
假设ECU的0x2A周期读取正响应有23字节需要传回诊断仪(SID=0x6A,即0x2A的正响应):
Step 1: ECU → 诊断仪 FF(第一帧)
┌──────┬──────┬────────────────────────────┐
│ 0x10 │ 0x17 │ data[0..5] (前6字节) │
│ FF │ len= │ │
│ │ 0x17 │ │
│ │ =23 │ │
└──────┴──────┴────────────────────────────┘
PCI: 0x1000 + (0x17&0xFF) = 0x1017
高4位=1(FF) + 低12位=0x017=23字节总长
Step 2: 诊断仪 → ECU FC(告诉ECU:继续发)
┌──────┬──────┬────────┐
│ 0x30 │ 0x00 │ 0x00 │
│ FC │ BS=0 │ STmin= │
│ CTS │ 不限 │ 0 │
└──────┴──────┴────────┘
Step 3: ECU → 诊断仪 CF(SN=1)
┌──────┬────────────────────────────┐
│ 0x21 │ data[6..12] (7字节) │
└──────┴────────────────────────────┘
Step 4: ECU → 诊断仪 CF(SN=2)
┌──────┬────────────────────────────┐
│ 0x22 │ data[13..19] (7字节) │
└──────┴────────────────────────────┘
Step 5: ECU → 诊断仪 CF(SN=3)
┌──────┬────────────────────────────┐
│ 0x23 │ data[20..22] (最后2字节) │ ← 剩余填补任意值
└──────┴────────────────────────────┘
Done: 诊断仪的CanTp层收齐全部23字节→通知UDS层→N_USData.indication
时序参数:N_As, N_Ar, N_Bs, N_Cr, N_Br
ISO 15765-2定义了几个关键时序参数来确保链路稳定性:
| 参数 | 含义 | 典型值 |
|---|---|---|
| N_As | 发送端将一帧CAN报文成功送上总线的时间 | 25ms |
| N_Ar | 接收端确认收到一帧并给出响应的处理时间 | 25ms |
| N_Bs | 发送端发出FF后等待接收端回复FC的最大时间 | 250ms (典型) |
| N_Br | 发送端收到FC后准备发出后续CF的时间间隔 | — |
| N_Cr | 接收端连续接收CF帧的间隔超时 | 25ms |
简化为实际操作中的理解:诊断仪->ECU的传输层如果250ms内不回复FC或CF——此次传输序列被放弃。
| 超时事件 | 诊断仪行为 | ECU行为 |
|---|---|---|
| N_Bs超时(发送FF后收不到FC) | 放弃传输,报告传输层超时,断开会话或重试 | — |
| N_Cr超时(接收端等待下一帧CF超时) | — | 放弃接收,释放缓冲区,诊断仪的下一次请求会收到NRC 0x78或直接超时 |
| N_As超时(发送帧未被CAN控制器确认) | 重发或报总线故障 | 重发或报总线故障 |
功能寻址与多帧——不能混用
ISO 15765-2支持单帧SF用于功能寻址——向多个ECU同时发请求。但FF(巨帧)只能在物理寻址上使用——因为只有一个ECU会回复FC, 如果有多个ECU同时回复FC,两个FC帧会相互碰撞(CAN仲裁)。因此重要规则:功能寻址 = 只能用SF单帧,物理寻址 = 可用FF巨帧。
本篇小结
- ISO 15765-2用四种帧类型解决CAN总线上的消息分段问题:SF(短消息)、FF(首帧宣告总长度)、CF(数据段+序列号)、FC(接收方流控)。
- FC的CTS/WT/OVFLW机制将流控主动权完全交给接收端——由ECU根据缓冲区状态决定是否需要发送方慢一点或暂停一下。
- SN序列号用于检测CF丢帧——如果ECU收到非预期的SN, 将请求发送端重传整个块。
- 功能寻址不能使用FF巨帧——只能使用SF单帧最多7字节。
【下集预告】:我们在上一节学了CAN信使的工作原理。现在我们把整套UDS请求挂在它的背上跑完一个完整的多帧交互——从ECU收到FF帧开始—到最后的CF帧被粘合回原样。