RS485 协议
本页对应仓库内 2026-10-27 的固件快照。原工程后续版本对磁铁状态和数据有效性有更新,尚未同步到本仓库;对接实物前请核对实际固件和协议版本。
这块板通过半双工 RS485 通信,应用协议是我们自己定义的二进制格式。CRC 使用 CRC-16/MODBUS 算法,但帧头、地址和命令格式是项目自己的设计,不能直接用 Modbus RTU 主站读取。
第一次接这块板,可以先按末尾的通信步骤读一下设备信息,再对照十六进制例子看每个字段。然后换用编码器时,帧格式相同,但测量类型、单位和校准内容会变。
想对照代码看,定义在 rs485_proto.h,实际处理在 rs485_proto.c。广播等细节按实现说明。
串口与默认配置
- MCU 串口为 USART0:PA9/TX、PA10/RX,8 数据位、无校验、1 停止位,即 8N1。
- PB5 控制收发方向;高电平发送,低电平接收。源码说明 SIT3088 的 DE 与 RE# 接在一起。主机通常使用自动收发 USB-RS485 适配器。
- 未保存配置或 Flash 配置校验失败时:ID=1,115200 bit/s,轮询模式,周期参数 20 ms,角度测量类型。
- 波特率参数是索引:
0→9600、1→19200、2→38400、3→57600、4→115200、5→230400、6→460800、7→921600。
依据:默认配置,第 143 行,UART 配置,第 393 行,波特率表,第 52 行。接口供电、A/B 接线和端接电阻应再对照实际硬件,软件引脚定义不能代替接线图。
帧格式
所有多字节字段均为小端;有符号整数用二进制补码。
偏移 长度 字段
0 1 A5
1 1 5A
2 1 DST:目标设备地址
3 1 SRC:源设备地址
4 1 TYPE:测量类型
5 1 CMD:命令
6 1 SEQ:8 位序号
7 1 LEN:DATA 的字节数
8 LEN DATA
8+LEN 1 CRC 低字节
9+LEN 1 CRC 高字节
LEN≤32,整帧长 10+LEN,最大 42 字节。CRC 从 DST 开始,到 DATA 最后一个字节结束,不包含 A5 5A 和 CRC 自身。初始值 0xFFFF,逐位右移,多项式 0xA001,无最终异或;校验向量 CRC("123456789")=0x4B37,线上顺序为 37 4B。
依据:CRC,第 75 行,发送组帧,第 489 行。可用 独立教学实现 和 协议检查 重算本文实例。
先用动画看一下请求、方向切换和应答的关系。速度已放慢,不表示真实收发时序。
地址、类型和应答
- 主机地址使用
0x00;设备 ID 为1..254;DST=0xFF为广播。 TYPE=0x01是角度编码器,0x02是直线位置,0xFF是任意类型。设备只处理当前类型或0xFF。- 同一总线所有传感器都应有唯一 ID。指定类型能减少不同类型误应答,不能替代唯一地址。
- 普通应答:
DST=请求SRC,SRC=设备当前ID,TYPE=当前测量类型,CMD=请求CMD|0x80,SEQ=请求SEQ。 - 应答 DATA 第一字节是状态;状态成功才按该命令的布局解析后续内容。
- SEQ 用于关联事务,8 位回卷;固件没有请求去重功能。超时重发的设置命令可能再次执行和写 Flash。
特别注意:SET_ID 的成功应答源地址已经是新 ID;SET_PROFILE 的成功应答类型已经是新类型。写主机时需要为这两种事务匹配预期的新标识。SET_BAUD 先按旧波特率发应答,再切到新波特率。
依据:地址与类型过滤,第 606 行,设置 ID,第 650 行,应答与波特率切换,第 967 行。
广播
固件直接忽略以下广播命令:GET_INFO、GET_DATA、GET_CAL、SET_ID、SET_BAUD、FACTORY。广播不会用于发现设备或批量分配 ID。
其余已实现设置命令可执行广播,但不回成功或错误应答;仍受 TYPE 过滤和参数检查约束。广播切换模式时应先理解其清除校准的影响。多设备教学优先采用逐台、逐地址轮询。
依据:广播排除列表,第 616 行,广播不应答,第 968 行。
命令
下文 u8/u16/i16/i32 分别是无符号 8 位、无符号 16 位、有符号 16 位和有符号 32 位。所列成功返回内容均在状态字节之后。
基本通信与配置
0x01 GET_INFO:请求为空;返回类型u8、IDu8、上传模式u8、波特率索引u8、周期 msu16、固件版本u16、校准有效u8、标志u8、机械零点 2 字节。应答 DATA 共 13 字节。版本常量为0x0101,当前上位机显示为 1.1。零点在角度模式按u16解读,在直线模式按i16解读。0x02 SET_ID:请求新 IDu8,范围 1..254;成功返回新 IDu8。自动保存。0x03 SET_BAUD:请求索引u8,范围 0..7;成功返回索引u8。自动保存,旧波特率应答后立即切换。0x04 SET_MODE:请求上传模式u8加周期 msu16;模式 0=轮询,1=主动上报,周期范围 5..60000 ms,即使模式 0 也要求周期合法。返回同样三字节。自动保存。0x05 SAVE:请求为空;保存当前配置,无额外成功数据。0x06 FACTORY:请求为空;恢复 ID=1、115200、轮询、20 ms、角度模式,清两种模式零点和校准并保存;返回新 IDu8、波特率索引u8。若原波特率不同,同样先按旧波特率应答。0x07 SET_PROFILE:请求类型u8,只允许 1 或 2;成功返回当前类型u8。真正切换到另一类型时会清除两种模式的零点与校准并保存;请求已经处于的同一类型时直接返回,不清除、不重写。
依据:基本命令,第 626 行,模式切换,第 902 行,清理两种校准,第 251 行。
采样与主动上报
0x10 GET_DATA:请求为空;成功应答 DATA 是status + sample,共 14 字节。0x30 REPORT:设备主动发送,目标0x00;DATA 仅为 sample,共 13 字节,没有状态字节。它的 SEQ 是设备独立递增的上报序号。
sample 内偏移 类型 内容
0 i32 角度或位置整数
4 i16 幅度,ADC 计数
6 u16 U1 ADC 原码
8 u16 U2 ADC 原码
10 u16 U4 ADC 原码
12 u8 flags
TYPE=1 时 value/100 为度,value×π/18000 为 rad;TYPE=2 时 value/100 为 mm,value×0.00001 为 m。变量名 angle_cdeg 在直线模式中仍被复用,不能按名字判断单位。
幅度不是磁感应强度的 T 或 mT;它是用于判断信号强弱的 ADC 计数,线上按 i16 打包且执行饱和裁剪。原码是 12 位 ADC 结果,协议用 u16 承载。
依据:采样打包,第 522 行,数据应答,第 758 行,主动上报,第 1065 行,采样结构,第 45 行。
零点、校准和直线模型宽度
0x21 SET_ZERO:请求为空时捕获当前原始测量作为机械零点;也可传入 2 字节零点偏移。角度为u16、0..35999、单位 0.01°;直线为i16、单位 0.01 mm。它设置的是从原始读数中减掉的偏移,不是命令“当前位置显示指定数值”。返回已存零点 2 字节并自动保存。0x22 CLEAR_ZERO:请求为空;将当前模式零点设为 0,自动保存;无额外成功数据。0x23 CAL_BEGIN:请求为空;开始角度峰峰值采集或直线零磁场基线采集;此时不写 Flash。角度需转满至少一圈;直线需先拿开磁铁。0x24 CAL_END:请求为空;校准成功后自动保存,返回offset[3](三个 i16)和gain[3](三个 u16),DATA 共 13 字节。数据不足返回 0x04 并保持校准进行状态;未开始就结束返回 0x03。0x25 CAL_CLEAR:请求为空;清除当前模式校准并自动保存。直线回到基线 2048;零点和敏感宽度保留。0x26 GET_CAL:请求为空;返回flags u8 + offset[3] i16 + gain[3] u16,DATA 共 14 字节。比CAL_END多了一个 flags,解析偏移不能共用。0x27 SET_SIGMA:仅直线模式;请求敏感宽度u16,单位 µm、范围 2000..30000,默认 8000;返回宽度u16并保存。GUI 用 mm 显示,所以 8 mm 对应请求整数 8000。
角度模式的 offset 是每路偏置,gain 是 Q12 相对增益,4096=1.0。直线模式复用这些槽位:offset 为三路零磁场基线;gain[0] 为宽度 µm,gain[1] 和 gain[2] 为 0;不能把 8000 解读为 Q12 增益。
依据:零点与校准,第 768 行,GET_CAL,第 883 行,宽度设置,第 931 行,直线校准导出,第 556 行。
状态码和标志
状态码描述命令是否执行成功:
0x00成功。0x01载荷长度错误。0x02参数超范围。0x03当前状态不允许,例如在角度模式设置直线宽度。0x04校准数据不足。0x05Flash 写入失败。0x06未知命令。
flags 描述测量状态,多个位可同时置位:bit0/0x01 磁场弱;bit1/0x02 校准有效;bit2/0x04 校准进行中;bit3/0x08 直线超出阵列或有效插值条件。
状态成功后仍要检查弱磁、越界和校准标志。CRC 通过不代表位置正确;误差和使用条件见校准与测量。固件没有硬件采样时间戳、温度补偿质量字段或磁铁在位确认字段。
依据:状态定义,第 122 行,flags 定义,第 37 行。
收发、超时与保存
设备发帧前拉高 PB5 并用软件忙等约 50 µs,发完等待发送完成,再忙等约 50 µs 后拉低回接收。这是代码里的近似延时,应通过逻辑分析仪核对实际波形。
固件有 128 字节接收环(保留一个空槽,有效容量 127);满时新字节被丢弃,无可查询溢出计数。拼帧长超过 32、CRC 错误、地址/类型不匹配均静默丢弃,不返回错误帧;已通过 CRC 且属于本机的错误命令才可能返回状态码。主循环处理残留拼帧时,距上次处理超过 20 ms 会清掉不完整帧。
主动上报要求距最近接收和发送各至少 3 ms、本轮没有应答且不在拼帧中。这只是本机避让,没有完整总线仲裁;一条总线上同时只启用一台主动上报设备,多节点采用主机逐一轮询。
周期参数是调度目标。115200/8N1 下,23 字节上报的纯线速时间约 2.00 ms;24 字节采样应答约 2.08 ms。轮询还需 10 字节请求约 0.87 ms,以及方向切换、运算和主机延迟。9600 下同一上报约需 24 ms,所以参数允许 5 ms 不代表所有波特率都能做到 200 Hz,更不代表 ADC 同步采样频率。
写 Flash 的命令应留出不少于 100 ms 的超时;原 GUI 通常留 300–500 ms。配置实际保存为最后一页地址 0x08007C00 上的 32 字节结构,带 magic/layout/CRC。读取失败时回默认值;当前实现是擦页后写入,无双份备份或掉电事务承诺。收到 Flash 错误后应回读配置与测量状态,不假定每条命令都完整回滚。不要在采样循环重复发送保存或模式设置。
依据:发送方向,第 459 行,接收缓冲,第 425 行,拼帧恢复,第 985 行,配置保存,第 319 行。
第一次通信
- 单设备接入,按已知 ID 和波特率发送
GET_INFO,类型先用 ANY。 - 确认返回 TYPE。固件出厂默认角度;直线 PCB 应明确切换到类型 2,再重新读取信息。
- 按对应方法校准;直线先拿走磁铁采基线,再放回磁铁调宽度;角度转满至少一圈。
- 确认旗标与机械安装,设置机械零点;再用
GET_DATA轮询采集。 - 主机按返回类型转换为 m 或 rad,并附主机接收时间。断链时停止产出新位置,进入上层故障处理。
- 更换 PCB 为角度构型后,通信帧仍可复用;切换类型、重做校准和零点,并改变单位解释。
十六进制样例
以下帧由代码构造,CRC 已与原上位机 crc16 独立核对,未连接板卡抓包。
读取 ID=1 的信息,TYPE=ANY,SEQ=1:
A5 5A 01 00 FF 01 01 00 61 8E
当前为角度类型 1 时,切换至直线类型 2,SEQ=3;成功应答已使用新类型 2:
请求:A5 5A 01 00 01 07 03 01 02 47 25
应答:A5 5A 00 01 02 87 03 02 00 02 C5 72
读取 ID=1 的直线采样,SEQ=2。构造应答值为 -1250,即 -12.50 mm=-0.0125 m;幅度 1000,U1/U2/U4 为 2048/2200/2500,flags=2:
请求:A5 5A 01 00 02 10 02 00 00 D7
应答:A5 5A 00 01 02 90 02 0E 00 1E FB FF FF E8 03 00 08 98 08 C4 09 02 59 BE
同一采样的主动帧没有状态字节,LEN=0x0D,SEQ=7:
A5 5A 00 01 02 30 07 0D 1E FB FF FF E8 03 00 08 98 08 C4 09 02 09 CA
设置直线敏感宽度 8000 µm,SEQ=6:
A5 5A 01 00 02 27 06 02 40 1F 65 62
若设备实际仍为角度类型,使用角度 TYPE 请求 SET_SIGMA 会收到状态 3;TYPE 写错成直线则会被静默忽略:
角度设备的状态错误应答:A5 5A 00 01 01 A7 06 01 03 A5 F5
设置 20 ms 主动上报和恢复 20 ms 轮询分别为:
主动:A5 5A 01 00 02 04 04 03 01 14 00 8A 60
轮询:A5 5A 01 00 02 04 05 03 00 14 00 E6 60
角度模式读数请求的对照帧(TYPE=1、SEQ=1)为 A5 5A 01 00 01 10 01 00 00 63。它与直线请求复用相同命令,数据的物理含义由类型决定。
继续阅读:上位机与独立读取示例 · 机器人接入。
