4. J1939报文格式

J1939 的报文格式是整门课程的“语法基础”。如果只把 CAN 帧看成 8 字节数据,那么 J1939 就是在 CAN 之上定义了一套“谁在说、说什么、对谁说、有多急”的完整语义。理解 PDU、PGN、SPN、优先级、源地址与目标地址之间的关系,是后续做节点通信、报文解析、故障诊断和网络设计的前提。

一、核心原理:从 CAN 帧到 J1939 协议数据单元

J1939 使用扩展 CAN 帧,29 位标识符被划分为多个字段,整体称为协议数据单元(PDU)。PDU 由七个部分组成:优先级(P)、保留位(R)、数据页(DP)、PDU 格式(PF)、PDU 特定(PS)、源地址(SA)以及数据场。其中 PF 和 PS 共同决定报文属于哪一类,并进一步映射为参数组编号(PGN)。

PDU 分为两种格式:PDU1 和 PDU2。PDU1 的 PF 值小于 240,此时 PS 字段表示目标地址,因此 PDU1 报文是点对点通信;PDU2 的 PF 值在 240 到 255 之间,此时 PS 字段作为组扩展,与 PF 一起构成 PGN,因此 PDU2 报文是广播通信。这个区别非常关键:同样是 29 位 ID,PDU1 的 PS 是“给谁”,PDU2 的 PS 是“说什么”。

PDU 字段速记:P(3 位优先级)→ R(1 位保留)→ DP(1 位数据页)→ PF(8 位 PDU 格式)→ PS(8 位 PDU 特定)→ SA(8 位源地址)→ 数据场(0~8 字节,J1939-22 可更长)。

二、PGN 与 SPN:参数组与可疑参数的层级关系

PGN 是参数组编号,用于标识一组相关参数。它由保留位、数据页、PDU 格式和 PDU 特定字段共同计算得到。对于 PDU1 报文,PGN 的 PS 字段通常置 0;对于 PDU2 报文,PS 字段参与 PGN 计算。PGN 是“报文级别”的标识,例如发动机转速、车速、水温等往往属于某个 PGN 下的多个 SPN。

SPN 是可疑参数编号,用于标识 PGN 内部的具体参数。一个 PGN 可以包含多个 SPN,每个 SPN 有明确的数据长度、分辨率、偏移量和单位。例如 PGN 61444(电子发动机控制器 1)中包含 SPN 190(发动机转速)、SPN 513(实际发动机扭矩百分比)等。诊断时读取到的故障码往往指向 SPN,而通信时传输的是 PGN 报文。

概念作用典型示例关系
PDU29 位标识符的整体结构P、R、DP、PF、PS、SA承载 PGN 的容器
PGN标识一组参数报文61444、65262由 PF、PS、DP 计算
SPN标识 PGN 内具体参数190、513、110隶属于某个 PGN
优先级决定总线仲裁顺序0~7,默认 6数值越小优先级越高
源地址标识发送节点0、3、128报文发出方
目标地址标识接收节点PDU1 的 PS 字段仅点对点报文有效

三、优先级、源地址与目标地址的工程含义

优先级占 3 位,取值范围 0~7,数值越小优先级越高。J1939 默认优先级为 6,安全相关或实时性要求高的报文会使用更高优先级,例如制动、转向等。优先级直接影响 CAN 总线仲裁:当多个节点同时发送时,标识符数值越小越容易赢得仲裁。因此,优先级不是“软件标签”,而是会改变物理层竞争结果的硬约束。

源地址 SA 占 8 位,标识发送该报文的节点地址。J1939 地址范围通常为 0~253,其中 254 表示空地址,255 表示全局地址。源地址必须唯一,否则会出现地址冲突。目标地址 DA 只在 PDU1 报文中出现,用于指定接收方;PDU2 报文没有目标地址,属于广播,所有节点都可以根据 PGN 决定是否接收。

下面这张图展示了 29 位标识符中 PDU 字段的划分,以及 PDU1 与 PDU2 在 PS 字段上的分叉关系。图中同时标出 PGN 的计算路径和 SPN 的归属层级,便于把“位字段—PGN—SPN”三者对应起来。

J1939 29 位标识符:PDU 字段划分与 PGN/SPN 映射 P 3 位 R 1 位 DP 1 位 PF 8 位 PS 8 位 SA 8 位 数据场 0~8 字节 PDU1:PF < 240 PS = 目标地址 DA 点对点通信,PGN 中 PS 置 0 PDU2:PF ≥ 240 PS = 组扩展 GE 广播通信,PS 参与 PGN 计算 PGN = DP + PF + PS(PDU2) 参数组编号:标识一组相关参数报文 SPN 190 发动机转速 SPN 513 实际发动机扭矩百分比 SPN 110 发动机冷却液温度 一个 PGN 可包含多个 SPN;SPN 是诊断与标定的最小参数单位

四、案例与场景:解析一条发动机转速报文

假设总线上出现一条扩展帧,标识符为 0x0CF00400。按 J1939 规则拆解:优先级 P = 0x0C 的高 3 位,即 3;DP = 0;PF = 0xF0,即 240;PS = 0x04;SA = 0x00。由于 PF = 240,属于 PDU2,PS 参与 PGN 计算。PGN = DP(0) + PF(0xF0) + PS(0x04) = 0x00F004,即 61444。该 PGN 对应“电子发动机控制器 1”,其中 SPN 190 表示发动机转速,位于数据场第 4、5 字节,分辨率 0.125 rpm/bit,偏移量 0。

标识符:0x0CF00400
二进制字段划分:
  优先级 P  = 0x0C >> 5 = 3
  保留位 R  = 0
  数据页 DP = 0
  PF        = 0xF0 = 240  → PDU2
  PS        = 0x04
  SA        = 0x00
PGN = DP + PF + PS = 0x00F004 = 61444
SPN 190 发动机转速:数据场第 4~5 字节,0.125 rpm/bit

如果同一标识符中 PF 小于 240,例如 0x18EAFF00,则 PF = 0xEA = 234,属于 PDU1,PS = 0xFF 表示全局目标地址,SA = 0x00。此时 PGN 计算时 PS 置 0,得到 PGN = 0x00EA00 = 59904,即“请求 PGN”。这说明 PDU1 与 PDU2 在 PGN 计算上的差异会直接影响解析结果。

五、常见误区与复盘

  • 误区一:把 PS 一律当作目标地址。只有 PDU1 的 PS 才是目标地址;PDU2 的 PS 是组扩展,参与 PGN 计算。
  • 误区二:把 PGN 和 SPN 混为一谈。PGN 是报文级标识,SPN 是参数级标识;一个 PGN 下可以有多个 SPN。
  • 误区三:忽略优先级对仲裁的影响。优先级数值越小越优先,默认 6,安全报文常用 3 或更高。
  • 误区四:源地址重复。同一总线上源地址必须唯一,否则会出现通信冲突和诊断混乱。
  • 误区五:PDU1 报文误当广播处理。PDU1 是点对点,目标地址不匹配的节点不应接收。

工程建议:解析 J1939 报文时,先看 PF 判断 PDU1/PDU2,再决定 PS 是目标地址还是组扩展,最后计算 PGN 并查表定位 SPN。这个顺序可以避免绝大多数解析错误。

注意:J1939-22 引入了更长的数据场和新的帧格式,但传统 29 位 ID 的 PDU、PGN、SPN 体系仍是理解 J1939 通信的基础。实际项目中应结合具体协议版本和 DBC 文件确认字段定义。

掌握 PDU、PGN、SPN、优先级、源地址与目标地址之间的关系后,就能从一条原始 CAN 报文中读出“谁发的、发给谁、什么优先级、属于哪个参数组、包含哪些参数”。这是后续进行节点地址管理、报文调度、故障诊断和网络负载分析的核心能力。