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 报文。
| 概念 | 作用 | 典型示例 | 关系 |
|---|---|---|---|
| PDU | 29 位标识符的整体结构 | 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”三者对应起来。
四、案例与场景:解析一条发动机转速报文
假设总线上出现一条扩展帧,标识符为 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 报文中读出“谁发的、发给谁、什么优先级、属于哪个参数组、包含哪些参数”。这是后续进行节点地址管理、报文调度、故障诊断和网络负载分析的核心能力。