串口二进制协议
串口类接口(RS-232、TTL、RS-485、USB 虚拟串口)都按 HiPNUC 二进制协议输出数据帧。各型号提供的接口见适用产品。
帧格式
| 域 | 值 | 长度(字节) | 说明 |
|---|---|---|---|
| SOF | 5A A5 | 2 | 帧头同步标志 |
| LEN | 1–512 | 2 | 数据域长度,小端,不含帧头、长度和 CRC |
| CRC | — | 2 | 16 位 CRC,小端,算法见 CRC 校验 |
| 数据域 | — | 1–512 | 第 1 字节是标签(tag),决定后续数据的类型与长度 |
- 所有多字节数值都是小端,浮点为 IEEE-754 单精度(
float)。整帧最大 518 字节。 - 标签
0x91是 HI91,0x83是 HI83。遇到不认识的标签,按 LEN 跳过整帧。
浮点型数据帧(HI91)
HI91 的数据域固定 76 字节,整帧 82 字节。内容是状态、温度、加速度、角速度、磁场、气压和融合后的姿态。测量值已经过出厂校准,不是芯片寄存器的原始读数;测量值与姿态都按输出数据轴向表达。
| 偏移 | 名称 | 类型 | 大小 | 单位 | 说明 |
|---|---|---|---|---|---|
| 0 | tag | u8 | 1 | — | 数据标签 0x91 |
| 1 | main_status | u16 | 2 | — | 状态字,见 MAIN_STATUS 状态字 |
| 3 | temperature | i8 | 1 | °C | 模块平均温度,整数 |
| 4 | air_pressure | float | 4 | Pa | 气压 |
| 8 | system_time | u32 | 4 | ms | 时间戳,含义见时间与时间戳 |
| 12 | acc_b | float | 4×3 | G | 加速度 XYZ,1 G ≈ 9.8 m/s² |
| 24 | gyr_b | float | 4×3 | deg/s | 角速度 XYZ |
| 36 | mag_b | float | 4×3 | μT | 磁场 XYZ |
| 48 | roll | float | 4 | deg | 横滚角 |
| 52 | pitch | float | 4 | deg | 俯仰角 |
| 56 | yaw | float | 4 | deg | 航向角,±180°,正方向见航向约定 |
| 60 | quat | float | 4×4 | — | 四元数 WXYZ |
HI91 与 HI83 的单位不同,对照和换算见数据字典与跨协议解码易错点。
可变类型数据帧(HI83)
HI83 由每帧头部的 data_bitmap 决定包含哪些数据段,所以帧长随配置变化。需要微秒时间戳、UTC、倾角或 MRU 数据,或想按需控制带宽时,选用 HI83。字段由 LOG HI83 MAP 设置,见 HI83 字段选择。
帧头与解析规则
固定头部 8 字节,其后按 bit 从低到高的顺序拼接被选中的数据段。未选中的段不出现,整帧相应变短。
| 偏移 | 名称 | 类型 | 大小 | 说明 |
|---|---|---|---|---|
| 0 | tag | u8 | 1 | 数据标签 0x83 |
| 1 | main_status | u16 | 2 | 状态字,见 MAIN_STATUS 状态字 |
| 3 | ins_status | u8 | 1 | 组合导航状态,供 INS 产品使用;IMU / AHRS 解析时忽略 |
| 4 | data_bitmap | u32 | 4 | 数据段位图 |
| 8 | … | — | 变长 | 按位序排列的数据段 |
解析时遵守四条:
- 每帧读取自己的
data_bitmap,按置位的段逐段累加偏移。MAP 一改,下一帧的长度随之变化,所以不要写死帧长,也不要用自己请求的 MAP 代替帧头位图。 - 位图中出现本手册未定义的位时,各段长度无法确定,丢弃整帧。
- 累加偏移不得超过 LEN,超出时按错误帧丢弃。
utc段何时有效,见 MAIN_STATUS 状态字的UTC_UNSYNC位。
data_bitmap 位定义
位图置位的段一定在帧里;产品不具备对应功能时,该段的值可能为 0 或无物理意义。
| 位 | 名称 | 类型 | 大小 | 单位 | 说明 |
|---|---|---|---|---|---|
| 0 | acc_b | float | 4×3 | m/s² | 加速度 XYZ |
| 1 | gyr_b | float | 4×3 | rad/s | 角速度 XYZ |
| 2 | mag_b | float | 4×3 | μT | 磁场 XYZ |
| 3 | rpy | float | 4×3 | deg | 欧拉角 roll / pitch / yaw,yaw ±180° |
| 4 | quat | float | 4×4 | — | 四元数 WXYZ |
| 5 | system_time_us | u64 | 8 | μs | 本地高分辨率时间戳,开机累计,不受对时影响 |
| 6 | utc | — | 8 | — | 年偏移(u8,年 − 2000)、月(u8)、日(u8)、时(u8)、分(u8)、秒与毫秒合计(u16,单位 ms,如 12.345 s 记为 12345)、保留(u8) |
| 7 | air_pressure | float | 4 | Pa | 气压 |
| 8 | temperature | float | 4 | °C | 模块平均温度 |
| 9 | inclination | float | 4×3 | deg | 倾角输出:X 轴倾角、Y 轴倾角、航向角。第三个值是原始 yaw(±180°,逆时针为正,见航向约定),既不是 Z 轴倾角,也不是罗盘航向 |
| 10 | heave_surge_sway | float | 4×3 | m | MRU 位移:垂荡、纵荡、横荡 |
| 11 | heave_surge_sway_frq | float | 4×3 | Hz | MRU 频率:垂荡、纵荡、横荡 |
| 21 | att_std | float | 4×3 | deg | 姿态 1σ(绕世界系三个轴的姿态误差,非负)。前两项是水平倾斜不确定度,第三项是航向不确定度。排列顺序见下方说明 |
att_std(bit21)按世界系轴序排列,不按 roll / pitch / yaw 排列。COORD 0 下依次为东、北、天轴,6 轴 COORD 4 下依次为北、西、天轴。车头朝北时,COORD 0 的前两项分别对应俯仰、横滚的不确定度。其他朝向下,这两项是俯仰与横滚的混合。- 公开字段是 bit0–11 和 bit21,掩码
0x00200FFF。只能置位这些位,全开配置(如0xFFFFFFFF)会让帧长和字段语义无法按本手册解析。全部公开字段置位时,数据域 144 字节,整帧 150 字节,未超过数据域 512 字节的上限。 - 倾角(bit9)的含义和取值范围见倾角输出。MRU(bit10、11,MRU 型号)见 MRU 输出。
- -I2C 型号读取 HI83 的方法见 I2C 协议。
帧长示例
帧长 = 6(帧头、长度、CRC)+ 8(固定头部)+ 被选中各段之和。
例如 data_bitmap = 0x0000003B(acc_b、gyr_b、rpy、quat、system_time_us):各段 12 + 12 + 12 + 16 + 8 = 60 字节,数据域 8 + 60 = 68 字节,整帧 74 字节。各档带宽占用见输出带宽与波特率。
CRC 校验
采用 CRC-16/XMODEM(有的工具把它叫 CRC-16/CCITT,但初值 0xFFFF 的 CCITT-FALSE 是另一种算法,不能混用):多项式 0x1021,初值 0x0000,无输入 / 输出反转,无最终异或。校验范围是帧头(2)+ 长度(2)+ 数据域,不含 CRC 字段本身。
#include <stdint.h>
#include <stddef.h>
/* CRC-16/XMODEM, poly 0x1021, init 0x0000, no reflection, no final XOR.
* Pass the previous result as "crc" to continue over another buffer. */
uint16_t hipnuc_crc16(uint16_t crc, const uint8_t *buf, size_t len)
{
for (size_t i = 0; i < len; i++) {
crc ^= (uint16_t)buf[i] << 8;
for (int b = 0; b < 8; b++)
crc = (crc & 0x8000) ? (uint16_t)((crc << 1) ^ 0x1021) : (uint16_t)(crc << 1);
}
return crc;
}
/* frame[] holds one complete frame: SOF(2) LEN(2) CRC(2) payload(LEN).
* payload_len is the LEN field, not the whole frame length. */
int hipnuc_frame_crc_ok(const uint8_t *frame, uint16_t payload_len)
{
uint16_t crc = hipnuc_crc16(0, frame, 4); /* SOF + LEN */
crc = hipnuc_crc16(crc, frame + 6, payload_len); /* payload, skipping the CRC field */
return crc == (uint16_t)(frame[4] | (frame[5] << 8));
}自测:hipnuc_crc16(0, "123456789", 9) 应返回 0x31C3。CRC 总是校验失败时,先用这个值和下面的帧解析示例核对自己的实现。
帧解析示例(HI91)
一帧 HI91 共 82 字节:前 6 字节是帧头 / 长度 / CRC,其后 76 字节是数据域。示例采集于默认输出数据轴向(COORD 0)。这也是解析器测试向量使用的那一帧:
5A A5 4C 00 18 4A 91 08 14 23 09 A2 C4 47 08 15 1C 00 CC E8 61 BE 9A 35 56 3E 65 EA 72 3F 31 D0 7C BD 75 DD C5 BB 6B D7 24 BC 89 88 FC 40 01 00 6A 41 AB 2A 70 C2 96 D4 50 41 ED 03 43 41 41 F4 F4 C2 CC CA F8 BE 73 6A 19 BE F0 00 1C 3D 8D 37 5C 3F| 字段 | 类型 | 原始值 | 解析值 | 说明 |
|---|---|---|---|---|
| 帧头 | — | 5A A5 | — | 同步标志 |
| 数据域长度 | — | 4C 00 | 0x004C = 76 | 76 字节 |
| CRC | — | 18 4A | 0x4A18 | 小端,对 5A A5 4C 00 加数据域计算 |
| tag | — | 91 | 0x91 | 数据域起始 |
| main_status | u16 | 08 14 | 0x1408 | bit3 WB_CONV、bit10 MAG_AIDING、bit12 SOUT_PULSE 置位;bit0–2 COORD = 0。各位含义见 MAIN_STATUS 状态字 |
| temperature | i8 | 23 | 35 | °C |
| air_pressure | float | 09 A2 C4 47 | 100676 | Pa |
| system_time | u32 | 08 15 1C 00 | 1840392 | ms |
| acc_b x/y/z | float | CC E8 61 BE9A 35 56 3E65 EA 72 3F | −0.2206 / 0.2092 / 0.9489 | G |
| gyr_b x/y/z | float | 31 D0 7C BD75 DD C5 BB6B D7 24 BC | −0.0617 / −0.0060 / −0.0101 | deg/s |
| mag_b x/y/z | float | 89 88 FC 4001 00 6A 41AB 2A 70 C2 | 7.892 / 14.625 / −60.042 | μT |
| roll / pitch / yaw | float | 96 D4 50 41ED 03 43 4141 F4 F4 C2 | 13.052 / 12.188 / −122.477 | deg |
| quat w/x/y/z | float | CC CA F8 BE73 6A 19 BEF0 00 1C 3D8D 37 5C 3F | −0.4859 / −0.1498 / 0.0381 / 0.8602 | — |
CRC 校验应通过,acc_b 合成约 0.996 G。
