CAN 协议
概述与总线参数
新项目使用 J1939:上电后模块按默认周期广播数据,配置也用 J1939 报文完成。信号定义的 DBC 文件见开发资源。CAN FD 型号可另外启用 CANFD83 可变帧。CANopen 为定制固件,如需使用请联系我司,要点见附录。哪些型号提供 CAN、CAN FD 见适用产品,-I2C 型号不提供 CAN。
| 项目 | J1939 | CANFD83(仅 CAN FD 型号) |
|---|---|---|
| 标称速率 | 出厂 500 kbit/s | 同左,数据段出厂 4 Mbit/s |
| 帧类型 | 29 位扩展帧,8 字节 | FD + BRS 扩展帧,最长 64 字节 |
| 硬件 | 终端电阻、屏蔽、线序和收发器电平见产品硬件手册 | 同左 |
各 PGN 的出厂周期见 PGN 消息列表,节点地址见协议参数,其他出厂默认见出厂默认配置。集成前确认三件事:
- 终端电阻与应答节点:总线两端各接 120 Ω 终端电阻,并保证至少有一个会应答(ACK)的节点,例如 CAN 分析仪。总线上只有模块和一个未开启应答的监听器时,发送会失败,输出时断时续甚至停止,配置帧也可能没有应答。
- 总线负载:负载 ≈ 每帧位数 × 帧率 ÷ 波特率,8 字节扩展帧约 131 bit。默认四个 PGN 各 100 Hz 约 52 kbit/s,在 125 kbit/s 总线上已占约 42 %。开启更多 PGN 前,先加大各 PGN 的周期。
- 多台模块同总线:所有模块出厂节点地址都是 8。一次只接一台,改好节点地址并重启后,再接下一台。
速率或节点地址未知时,按失联恢复找回。节点地址未知时的做法是:对 1–127 逐个发送点对点请求,读参数地址 0x009C(节点地址),有应答的即是,请求格式见配置协议。
J1939
数据输出采用 SAE J1939 的 29 位扩展标识符。CANFD83 沿用同样的标识符布局,数据域另行定义。
帧格式
CAN_ID = (P<<26)|(R<<25)|(DP<<24)|(PF<<16)|(PS<<8)|SA所有数据 PGN 都是厂商自定义格式(PF = 0xFF,无目的地址的广播格式)。PS 为 PGN 低字节,SA 为模块的节点地址。优先级 3、节点 8 时,PGN 0xFF41 的 CAN ID = 0x0CFF4108。
警告
J1939 数据域为小端:32 位值 0x12345678 在帧中为 78 56 34 12。按大端解码不会报错,但数值全错。
协议参数
| 参数 | 值 | 说明 |
|---|---|---|
| 帧格式 | 29 位扩展帧 | 经典 PGN 为 CAN 2.0B、8 字节;CANFD83 为 CAN FD |
| 优先级 | 3 | 固定 |
| 节点地址 SA | 出厂 8 | 可设 1–127,须不同于主机源地址(本页示例用 0x55) |
PGN 消息列表
优先级 3 时 CAN ID 为 0x0CFF[PS][SA]。周期参数为 16 位,单位 ms,0 = 关闭,有效范围 1–32767。读写周期的方法见配置协议。
| PGN | PS | 名称 | 出厂周期 | 周期参数地址 | 适用 |
|---|---|---|---|---|---|
| 0xFF2F | 0x2F | 时间信息(UTC 或本地时间) | 关闭 | 0x012F | 全部 |
| 0xFF34 | 0x34 | 三轴加速度 | 10 ms | 0x0134 | 全部 |
| 0xFF37 | 0x37 | 三轴角速度 | 10 ms | 0x0137 | 全部 |
| 0xFF3A | 0x3A | 三轴磁场 | 关闭 | 0x013A | 带磁传感器的型号 |
| 0xFF3D | 0x3D | 横滚 / 俯仰角 | 10 ms | 0x013D | 全部 |
| 0xFF41 | 0x41 | 航向角 | 10 ms | 0x0141 | 全部 |
| 0xFF43 | 0x43 | 温度 | 关闭 | 0x0143 | 以型号为准 |
| 0xFF46 | 0x46 | 四元数 | 关闭 | 0x0146 | 全部 |
| 0xFF4A | 0x4A | 倾角输出 | 关闭 | 0x014A | 全部,见倾角输出 |
| 0xFF5B | 0x5B | CANFD83 可变帧 | 关闭 | 0x015B | 仅 CAN FD 型号 |
各 PGN 的数据域为 8 字节,字段如下。未列出的字节保留,不解析。
| PGN | 字节 | 字段 | 类型 | 比例因子 | 单位 |
|---|---|---|---|---|---|
| 0xFF2F | 0–5 | 年 − 2000 / 月 / 日 / 时 / 分 / 秒 | u8 × 6 | — | — |
| 6–7 | 毫秒 | u16 | 1 | ms | |
| 0xFF34 | 0–1 / 2–3 / 4–5 | 加速度 X / Y / Z | i16 | 0.00048828 | G |
| 0xFF37 | 0–1 / 2–3 / 4–5 | 角速度 X / Y / Z | i16 | 0.061035 | deg/s |
| 0xFF3A | 0–1 / 2–3 / 4–5 | 磁场 X / Y / Z | i16 | 0.030517 | μT |
| 0xFF3D | 0–3 | 横滚 Roll | i32 | 0.001 | deg |
| 4–7 | 俯仰 Pitch | i32 | 0.001 | deg | |
| 0xFF41 | 0–3 | 罗盘航向,0–360°,顺时针为正 | i32 | 0.001 | deg |
| 4–7 | 航向,±180°,逆时针为正 | i32 | 0.001 | deg | |
| 0xFF43 | 0–1 | 温度 | i16 | 0.01 | °C |
| 2–7 | 保留,请勿解析 | — | — | — | |
| 0xFF46 | 0–1 / 2–3 / 4–5 / 6–7 | 四元数 qw / qx / qy / qz | i16 | 0.0001 | — |
| 0xFF4A | 0–3 | X 轴倾角 | i32 | 0.001 | deg |
| 4–7 | Y 轴倾角 | i32 | 0.001 | deg |
- 加速度、角速度、磁场的满量程与比例因子见数据类型与比例因子。需要更高精度时,用 CANFD83 的 float32 字段,或串口的 HI91 / HI83。
- 0xFF41 两个航向的含义见航向约定;罗盘航向和倾角输出不受
COORD影响。 - 0xFF4A 的量程和用法见倾角输出。
- 0xFF2F 只在已对时时填年、月、日;年、月、日为 0 表示尚未对时,此时时、分、秒是本地 24 h 回绕时间,不能当作绝对 UTC。
- J1939 与 CANFD83 都不输出气压和 MRU 数据;MRU 型号用串口或 Modbus 读取,见 MRU 输出。
解码示例
| CAN ID | 数据 | 解码 |
|---|---|---|
0x0CFF3408 加速度 | EC FF 23 00 00 08 00 00 | X = 0xFFEC = −20 → −0.0098 G;Y = 0x0023 = 35 → 0.0171 G;Z = 0x0800 = 2048 → 1.0000 G(模块水平静止) |
0x0CFF4108 航向 | 6D DE 01 00 93 21 FE FF | 前 4 字节 0x0001DE6D = 122477 → 122.477°(顺时针);后 4 字节 0xFFFE2193 = −122477 → −122.477°(逆时针),两者描述同一航向(COORD 0) |
0x0CFF2F08 时间 | 1A 06 12 0E 1E 2D 58 02 | 2026-06-18 14:30:45.600 UTC(已完成 UTC 对时) |
示例的节点地址均为 8。完整的解码实现见 SDK 的 hipnuc_j1939.c 和接收示例 read_can.c,信号定义的 DBC 文件见开发资源。
CANFD83 可变帧
仅适用于 CAN FD 型号。默认标称速率 500 kbit/s,数据段速率 4 Mbit/s,以模块当前配置为准。总线上的其他设备须兼容 CAN FD。
PGN=0xFF5B,优先级 3,扩展 ID=0x0CFF5B00 | node_id,FD=1、BRS=1。
位时序:模块在各标称速率下的采样点均为 80 %,数据段为 80 %(5 Mbit/s 时为 75 %)。CAN FD 节点在标称段的采样点切换到数据段速率。主机的标称采样点须与模块一致,否则数据段从错开的位置开始采样,标称速率越低,错开越多。例如 250 kbit/s + 4 Mbit/s 时,75 % 与 80 % 之差约为 0.8 个数据位,足以使通信出错。
CANFD83 帧格式
固定头部 8 字节,随后按 MAP 位从低到高拼接所选字段。多字节整数及 IEEE 754 float32 均为小端。
| 偏移 | 字节数 | 字段 | 类型 | 说明 |
|---|---|---|---|---|
| 0 | 4 | MAP | uint32 | 本帧字段位图 |
| 4 | 2 | main_status | uint16 | 见 MAIN_STATUS,bit12 为 0 |
| 6 | 1 | ins_status | uint8 | 组合导航状态,供 INS 产品使用;IMU / AHRS 解析时忽略 |
| 7 | 1 | sequence | uint8 | 编码序号,每编码一帧加 1,0–255 回卷;序号不连续说明有帧丢失,不反映采样间断(采样间隔看 SYSTEM_TIME,MAP bit5) |
| bit | 字段 | 类型 | 字节数 | 单位 | 顺序 / 含义 |
|---|---|---|---|---|---|
| 0 | ACC_B | float32×3 | 12 | m/s² | X、Y、Z |
| 1 | GYR_B | float32×3 | 12 | rad/s | X、Y、Z |
| 2 | MAG_B | float32×3 | 12 | μT | X、Y、Z;需产品支持磁力计 |
| 3 | RPY | float32×3 | 12 | deg | roll、pitch、yaw;yaw 为 ±180° |
| 4 | QUAT | float32×4 | 16 | — | w、x、y、z |
| 5 | SYSTEM_TIME | uint64 | 8 | μs | 单调 IMU 采样时刻 |
| 6 | UTC | packed | 8 | — | 见下文 |
| 8 | TEMPERATURE | float32 | 4 | °C | 温度 |
UTC 布局:year-2000:u8、month:u8、day:u8、hour:u8、minute:u8、second*1000+ms:u16le、reserved:u8=0。无有效日期时 year=0。是否完成 PPS 对时只看 MAIN_STATUS 的 UTC_UNSYNC;该位为 1 时,不能当作绝对 UTC,各接口时间戳的含义见时间与时间戳。
MAP 支持位掩码为 0x0000017F。配置必须非零、不含保留位,且逻辑长度 8 + 所选字段字节数之和 ≤ 64。0x17F 全部选中为 92 字节。非法写入无效,原 MAP 保持不变,以读回为准。
默认 MAP=0x0000012B,逻辑长度 56 字节,总线长度 64 字节(DLC=15),尾部补零。其他配置同样向上取最近的合法长度,填充字节不参与解析。
| CAN FD 数据字节数 | 12 | 16 | 20 | 24 | 32 | 48 | 64 |
|---|---|---|---|---|---|---|---|
| DLC 编码 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
CANFD83 的配置方式
沿用配置协议,请求为经典 CAN、8 字节,FD=0、BRS=0。下表“地址”列为配置协议的参数地址。
| 参数 | 地址 | 默认 | 生效 |
|---|---|---|---|
| CANFD83 MAP | 0x0180 | 0x12B | 下一帧 |
| CANFD83 周期 | 0x015B | 0(关闭) | 立即,单位 ms |
| 周期输出总开关 | 0x009D | 1(开) | 立即,0/1 |
| 数据段速率索引 | 0x009B | 11 | 保存后重启 |
定时输出要求总开关为 1。周期取非零的 16 位值,单位 ms,0 表示关闭。数据段速率索引:0=1 Mbit/s、10=2 Mbit/s、11=4 Mbit/s、12=5 Mbit/s,只写表内值。标称速率的参数地址为 0x009A,速率码见配置协议。
节点地址 8、主机源地址 0x55:请求 ID=0x0CEF0855,响应 ID=0x0CEF5508。写入时模块回显请求,读取时返回当前值。
| 操作 | 请求数据(8 字节) |
|---|---|
| MAP = 0x12B | 80 01 06 00 2B 01 00 00 |
| 读取 MAP | 80 01 03 00 00 00 00 00 |
| 周期 = 10 ms | 5B 01 06 00 0A 00 00 00 |
报文示例
构造数据,非实测采集:ID=0x0CFF5B08、FD=1、BRS=1、DLC=15。
2B 01 00 00 00 00 00 7E
00 00 80 3F 00 00 00 C0
00 00 18 41 00 00 80 3E
00 00 00 BF 00 00 80 3F
00 00 20 41 00 00 A0 C1
00 00 F0 41 40 42 0F 00
00 00 00 00 00 00 CC 41
00 00 00 00 00 00 00 00解析:ACC_B=[1, -2, 9.5] m/s²,GYR_B=[0.25, -0.5, 1] rad/s,RPY=[10, -20, 30] deg,SYSTEM_TIME=1000000 μs,TEMPERATURE=25.5 °C。末尾 8 字节为填充。
配置协议
主机通过专用配置 PGN 读写模块参数,参数地址与 Modbus 寄存器地址一致。读写规则如下:
- 主机源地址用
0x55,优先级 3。 - 配置帧点对点发给模块的节点地址,不要广播写。
- 一次只发一条,收到应答或超时后再发下一条,帧间隔不少于 10 ms。
- 应答 ID 为
0x0CEF55<节点>,节点 8 即0x0CEF5508。 - 回显只代表模块收到了请求,不代表写入成功,关键参数写后回读确认。保存、重启和生效时机见配置流程与保存。
配置帧格式:CAN ID = 0x0CEF[DA][SA],DA 为模块节点地址,SA 为主机源地址。数据必须是 8 字节:
| 字节 | 字段 | 类型 | 说明 |
|---|---|---|---|
| 0–1 | ADDR | u16 | 参数地址,小端 |
| 2 | CMD | u8 | 0x06 写,0x03 读 |
| 3 | 保留 | u8 | 主机写 0,模块原样回显 |
| 4–7 | VAL | u32 | 数据值,小端 |
应答规则:
| 请求 | 应答 |
|---|---|
| 写、读 | CAN ID 0x0CEF55<节点>;写回显请求,读返回 ADDR + CMD + 当前值 |
| 地址或数值不合法 | 可能无应答,也可能照常回显,一律以读回为准 |
| 保存、复位、恢复出厂 | 不一定有回显,以重启后能否通信判断,处理方法见配置流程与保存 |
16 位参数:除 CANFD83 MAP(32 位)外,常用参数都是 16 位。写入时 VAL 高 16 位须为 0。读回时按有符号 16 位扩展为 32 位:16 位值的最高位为 1 时,读回的高 16 位为 FF FF。与写入值比较时,只取低 16 位。
常用配置(默认节点地址 8,请求 CAN ID 0x0CEF0855;[VAL] 为 4 字节 u32 小端,100 ms 写作 64 00 00 00)。数据的前两个字节是参数地址(小端),例如 9D 00 即参数地址 0x009D:
| 数据 | 说明 |
|---|---|
[PS] 01 06 00 [VAL] | 数据 PGN 的发送周期,[PS] 见 PGN 消息列表,如 37 01(参数地址 0x0137)为角速度。立即生效,0 = 关闭,有效范围 1–32767 ms,常用 5–1000 ms |
9D 00 06 00 [VAL] | 参数地址 0x009D,定时输出总开关:1 = 打开(出厂),0 = 关闭 |
9A 00 06 00 [VAL] | 参数地址 0x009A,标称速率码:0 = 1 Mbit/s、2 = 500 kbit/s、3 = 250 kbit/s、4 = 125 kbit/s。保存并重启后生效 |
9C 00 06 00 [VAL] | 参数地址 0x009C,节点地址 1–127,须不同于主机源地址。保存并重启后生效 |
5B 01 06 00 [VAL] | 参数地址 0x015B,CAN FD 型号的 CANFD83 周期,出厂关闭,见 CANFD83 |
80 01 06 00 [VAL] | 参数地址 0x0180,CAN FD 型号的 CANFD83 字段位图,见 CANFD83 |
9B 00 06 00 [VAL] | 参数地址 0x009B,CAN FD 型号的数据段速率索引,见 CANFD83。保存并重启后生效 |
06 00 06 00 [VAL] | 参数地址 0x0006,工作模式,取值见工作模式。保存并重启后生效 |
07 00 06 00 [VAL] | 参数地址 0x0007,输出数据轴向,取值见输出数据轴向。保存并重启后生效 |
A6 00 06 00 [VAL] | 参数地址 0x00A6,安装方向三位码(如 024 写作 18 00 00 00),见安装方向。只写安装方向表里的 24 个三位码,模块不一定校验写入值。保存并重启后生效。读回、验证姿态符号和重设零点的顺序见设置顺序 |
A5 00 06 00 [VAL] | 参数地址 0x00A5,姿态零点,取值同 CONFIG ATT RST,见姿态零点与校平 |
00 00 06 00 00 00 00 00 | 参数地址 0x0000(CTRL)写 0x0000,保存配置 |
00 00 06 00 01 00 00 00 | 参数地址 0x0000(CTRL)写 0x0001,恢复出厂,见恢复出厂 |
00 00 06 00 FF 00 00 00 | 参数地址 0x0000(CTRL)写 0x00FF,重启 |
警告
速率码只用 0、2、3、4,节点地址只用 1–127。表外的值会被拒绝。改后失联时见失联恢复。
→ 为主机发送,← 为模块应答。
示例:把角速度 PGN 改为 100 ms,并读回。
→ 0x0CEF0855 37 01 06 00 64 00 00 00 write period = 100 ms
← 0x0CEF5508 37 01 06 00 64 00 00 00 echo only, not a confirmation
→ 0x0CEF0855 37 01 03 00 00 00 00 00 read back
← 0x0CEF5508 37 01 03 00 64 00 00 00 current value = 100 ms示例:把节点地址从 8 改为 9。
→ 0x0CEF0855 9C 00 06 00 09 00 00 00 write node address = 9
← 0x0CEF5508 9C 00 06 00 09 00 00 00 echo only, not a confirmation
→ 0x0CEF0855 9C 00 03 00 00 00 00 00 read back before saving
← 0x0CEF5508 9C 00 03 00 09 00 00 00 value is 9 (still answered by node 8 until reboot)
→ 0x0CEF0855 00 00 06 00 00 00 00 00 SAVECONFIG
→ 0x0CEF0855 00 00 06 00 FF 00 00 00 REBOOT, no echo expected
(wait for restart, then address the new node)
→ 0x0CEF0955 9C 00 03 00 00 00 00 00 read node address
← 0x0CEF5509 9C 00 03 00 09 00 00 00 node address is now 9时间同步
PGN 0xFF2F 只用于输出模块当前时间,不能用它给模块对时。UTC 对时用 PPS 对时(PPS + 串口 RMC)。各接口时间戳的含义见时间与时间戳。
