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

第三章 传输层 —— 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 FrameSF0 0xxxxxxx (bit7=0)单帧——整个请求<=7字节数据
First FrameFF1 0001xxxx xxxxxxxx (高4位=1, 低12位=总长度)巨帧的第一帧——宣告“接下来共有NN字节“
Consecutive FrameCF2 xxxxxxxx (高4位=2)巨帧的后续分段——携带SN(序列号)
Flow ControlFC3 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巨帧


本篇小结

  1. ISO 15765-2用四种帧类型解决CAN总线上的消息分段问题:SF(短消息)、FF(首帧宣告总长度)、CF(数据段+序列号)、FC(接收方流控)。
  2. FC的CTS/WT/OVFLW机制将流控主动权完全交给接收端——由ECU根据缓冲区状态决定是否需要发送方慢一点或暂停一下。
  3. SN序列号用于检测CF丢帧——如果ECU收到非预期的SN, 将请求发送端重传整个块。
  4. 功能寻址不能使用FF巨帧——只能使用SF单帧最多7字节。

【下集预告】:我们在上一节学了CAN信使的工作原理。现在我们把整套UDS请求挂在它的背上跑完一个完整的多帧交互——从ECU收到FF帧开始—到最后的CF帧被粘合回原样。