跳转到内容
新建笔记

控制板与上位机通讯协议

参数值
物理接口RS232
波特率38400 bps
数据位8
停止位2
校验位无
流控制无
  • 字节序:大端序(Big-Endian,高字节在前)
  • 校验方式:CRC-16/MODBUS
  • 超时时间:1000ms(上位机等待控制板响应)
  • 重试次数:3次
  • 序列号范围:0x01~0xFF(循环使用,0x00保留)

┌──────┬──────┬──────┬──────┬────────┬──────┬──────┐
│ 帧头 │ 长度 │ 序号 │ 命令 │ 数据 │ CRC │ 帧尾 │
│ 2B │ 1B │ 1B │ 1B │ N字节 │ 2B │ 1B │
└──────┴──────┴──────┴──────┴────────┴──────┴──────┘
0xAA55 Len SeqNo CMD Data CRC16 0xEE
字段长度说明
帧头2B固定为 0xAA55,用于帧同步
长度1B数据区字节数(不含帧头、长度、CRC、帧尾)
序号1B流水号,范围 0x01~0xFF,用于匹配请求与响应
命令1B命令码,见命令码表
数据N字节命令相关数据,长度由”长度”字段指定
CRC2BCRC-16/MODBUS校验,计算范围:序号~数据区末尾
帧尾1B固定为 0xEE,用于帧结束标识
命令码命令名称方向说明
0x01启动命令上位机→控制板启动电机运行
0x81启动响应控制板→上位机启动命令执行结果
0x02停止命令上位机→控制板停止电机运行
0x82停止响应控制板→上位机停止命令执行结果
0x03查找脉冲命令上位机→控制板伺服标定
0x83查找脉冲响应控制板→上位机标定执行结果
0x04速度设置命令上位机→控制板设置加减速度
0x84速度设置响应控制板→上位机设置执行结果
0x05速度查询命令上位机→控制板查询当前速度
0x85速度查询响应控制板→上位机返回当前速度
0x10状态查询命令上位机→控制板查询控制板状态
0x90状态查询响应控制板→上位机返回状态信息

规则:响应命令码 = 请求命令码 | 0x80


类型字节数范围说明
UINT810~255无符号8位整数
UINT1620~65535无符号16位整数(大端序)
UINT3240~4294967295无符号32位整数(大端序)
参数名称类型范围单位说明
转速UINT160~10000RPM电机转速
角度UINT160~36000.1°停止角度,精度0.1度
加减速度UINT16100~5000RPM/s加减速度,过小或过大会被限制
状态码名称说明
0x00SUCCESS执行成功
0x01ERR_CYLINDER_UP气缸上升失败
0x02ERR_CYLINDER_DOWN气缸下降失败
0x03ERR_SERVO_TIMEOUT伺服响应超时
0x04ERR_SERVO_POSITION伺服位置偏差过大
0x05ERR_PARAM_RANGE参数超出范围
0x06ERR_INVALID_CMD无效命令
0x07ERR_CRC_ERRORCRC校验错误
0x08ERR_BUSY设备忙,拒绝执行
0x09ERR_NOT_READY设备未就绪
0xFFERR_UNKNOWN未知错误

功能:启动电机,设置目标转速

上位机 → 控制板

字段值/类型说明
帧头0xAA55固定
长度0x03数据区3字节
序号UINT8流水号
命令0x01启动命令
数据[0-1]UINT16目标转速(0~10000 RPM)
数据[2]UINT8启动模式(0x01=正常启动)
CRCUINT16CRC校验值
帧尾0xEE固定

控制板 → 上位机

字段值/类型说明
帧头0xAA55固定
长度0x04数据区4字节
序号UINT8与请求相同
命令0x81启动响应
数据[0]UINT8状态码
数据[1-2]UINT16实际转速(反馈值)
数据[3]UINT8运行状态(0x00=停止,0x01=运行)
CRCUINT16CRC校验值
帧尾0xEE固定

示例

请求:AA55 03 12 01 09C4 01 [CRC] EE
帧头 长度 序号 命令 2500RPM 模式 校验 帧尾
响应:AA55 04 12 81 00 09C4 01 [CRC] EE
帧头 长度 序号 命令 成功 2500RPM 运行 校验 帧尾

功能:停止电机,可选定位停止功能

上位机 → 控制板

字段值/类型说明
帧头0xAA55固定
长度0x04数据区4字节
序号UINT8流水号
命令0x02停止命令
数据[0]UINT8停止模式
0x00=立即停止
0x01=定位停止
数据[1-2]UINT16停止角度(0~3600,单位0.1°)
仅定位停止时有效
数据[3]UINT8保留,填0x00
CRCUINT16CRC校验值
帧尾0xEE固定

控制板 → 上位机

字段值/类型说明
帧头0xAA55固定
长度0x04数据区4字节
序号UINT8与请求相同
命令0x82停止响应
数据[0]UINT8状态码
数据[1-2]UINT16实际停止角度(反馈值)
数据[3]UINT8运行状态(0x00=已停止)
CRCUINT16CRC校验值
帧尾0xEE固定

示例

立即停止:
请求:AA55 04 13 02 00 0000 00 [CRC] EE
响应:AA55 04 13 82 00 0000 00 [CRC] EE
定位停止到180度:
请求:AA55 04 14 02 01 0708 00 [CRC] EE
(0x0708 = 1800 = 180.0度)
响应:AA55 04 14 82 00 0708 00 [CRC] EE

4.3 查找脉冲命令 (0x03/0x83)

跳转到“4.3 查找脉冲命令 (0x03/0x83)”

功能:执行伺服电机Z相脉冲查找,用于系统标定

上位机 → 控制板

字段值/类型说明
帧头0xAA55固定
长度0x01数据区1字节
序号UINT8流水号
命令0x03查找脉冲命令
数据[0]UINT8查找模式(0x01=标准模式)
CRCUINT16CRC校验值
帧尾0xEE固定

控制板 → 上位机

字段值/类型说明
帧头0xAA55固定
长度0x05数据区5字节
序号UINT8与请求相同
命令0x83查找脉冲响应
数据[0]UINT8状态码
数据[1-4]UINT32脉冲位置(编码器计数值)
CRCUINT16CRC校验值
帧尾0xEE固定

示例

请求:AA55 01 15 03 01 [CRC] EE
响应:AA55 05 15 83 00 00001234 [CRC] EE
状态成功,脉冲位置=0x00001234

4.4 速度设置命令 (0x04/0x84)

跳转到“4.4 速度设置命令 (0x04/0x84)”

功能:设置加减速度参数

上位机 → 控制板

字段值/类型说明
帧头0xAA55固定
长度0x03数据区3字节
序号UINT8流水号
命令0x04速度设置命令
数据[0-1]UINT16加减速度(100~5000 RPM/s)
数据[2]UINT8保留,填0x00
CRCUINT16CRC校验值
帧尾0xEE固定

控制板 → 上位机

字段值/类型说明
帧头0xAA55固定
长度0x03数据区3字节
序号UINT8与请求相同
命令0x84速度设置响应
数据[0]UINT8状态码
数据[1-2]UINT16实际设置的速度值
CRCUINT16CRC校验值
帧尾0xEE固定

示例

设置为1000 RPM/s:
请求:AA55 03 16 04 03E8 00 [CRC] EE
响应:AA55 03 16 84 00 03E8 [CRC] EE
状态成功,速度=1000

4.5 速度查询命令 (0x05/0x85)

跳转到“4.5 速度查询命令 (0x05/0x85)”

功能:查询当前加减速度设置

上位机 → 控制板

字段值/类型说明
帧头0xAA55固定
长度0x01数据区1字节
序号UINT8流水号
命令0x05速度查询命令
数据[0]UINT8保留,填0x00
CRCUINT16CRC校验值
帧尾0xEE固定

控制板 → 上位机

字段值/类型说明
帧头0xAA55固定
长度0x03数据区3字节
序号UINT8与请求相同
命令0x85速度查询响应
数据[0]UINT8状态码
数据[1-2]UINT16当前速度值
CRCUINT16CRC校验值
帧尾0xEE固定

示例

请求:AA55 01 17 05 00 [CRC] EE
响应:AA55 03 17 85 00 03E8 [CRC] EE
当前速度=1000 RPM/s

4.6 状态查询命令 (0x10/0x90)

跳转到“4.6 状态查询命令 (0x10/0x90)”

功能:查询控制板当前状态(可选扩展功能)

上位机 → 控制板

字段值/类型说明
帧头0xAA55固定
长度0x01数据区1字节
序号UINT8流水号
命令0x10状态查询命令
数据[0]UINT8保留,填0x00
CRCUINT16CRC校验值
帧尾0xEE固定

控制板 → 上位机

字段值/类型说明
帧头0xAA55固定
长度0x08数据区8字节
序号UINT8与请求相同
命令0x90状态查询响应
数据[0]UINT8运行状态
0x00=停止 0x01=运行 0x02=故障
数据[1-2]UINT16当前转速
数据[3-4]UINT16当前角度
数据[5]UINT8气缸状态
0x00=下 0x01=上 0xFF=异常
数据[6]UINT8伺服状态
0x00=离线 0x01=就绪 0xFF=故障
数据[7]UINT8保留
CRCUINT16CRC校验值
帧尾0xEE固定

从 序号 字段开始,到 数据区末尾 结束(不含帧头、长度、CRC、帧尾)

  • 多项式: 0xA001(反向多项式)
  • 初始值: 0xFFFF
  • 结果异或值: 0x0000
  • 字节序: 低字节在前
/**
* @brief 计算CRC-16/MODBUS校验值
* @param data: 数据指针
* @param length: 数据长度
* @return CRC校验值(16位)
*/
uint16_t crc16_modbus(const uint8_t *data, uint16_t length)
{
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++)
{
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++)
{
if (crc & 0x0001)
{
crc = (crc >> 1) ^ 0xA001;
}
else
{
crc = crc >> 1;
}
}
}
return crc;
}
/**
* @brief 校验接收到的数据帧
* @param frame: 完整帧数据(含帧头到帧尾)
* @param frame_len: 帧总长度
* @return 1=校验通过, 0=校验失败
*/
uint8_t verify_frame(const uint8_t *frame, uint16_t frame_len)
{
if (frame_len < 8) return 0; // 最小帧长度
// 检查帧头帧尾
if (frame[0] != 0xAA || frame[1] != 0x55) return 0;
if (frame[frame_len - 1] != 0xEE) return 0;
// 计算CRC(从序号到数据区末尾)
uint8_t data_len = frame[2]; // 长度字段
uint16_t calc_crc = crc16_modbus(&frame[3], data_len + 2);
// 提取帧中的CRC(低字节在前)
uint16_t frame_crc = frame[frame_len - 3] | (frame[frame_len - 2] << 8);
return (calc_crc == frame_crc) ? 1 : 0;
}
def crc16_modbus(data: bytes) -> int:
"""计算CRC-16/MODBUS"""
crc = 0xFFFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x0001:
crc = (crc >> 1) ^ 0xA001
else:
crc >>= 1
return crc
def build_frame(seq_no: int, cmd: int, data: bytes) -> bytes:
"""构建完整帧"""
length = len(data) + 2 # 序号+命令+数据长度
frame = bytearray([0xAA, 0x55, length, seq_no, cmd])
frame.extend(data)
# 计算CRC(从序号开始)
crc = crc16_modbus(frame[3:])
frame.append(crc & 0xFF) # CRC低字节
frame.append((crc >> 8) & 0xFF) # CRC高字节
frame.append(0xEE) # 帧尾
return bytes(frame)
# 示例:构建启动命令
seq = 0x12
cmd = 0x01
data = bytes([0x09, 0xC4, 0x01]) # 2500RPM, 模式1
frame = build_frame(seq, cmd, data)
print(frame.hex().upper())

上位机 控制板
| |
|------- 启动命令(序号=0x12) ------->|
| | 执行命令
|<------ 启动响应(序号=0x12) --------|
| |
| (等待操作完成) |
| |
|------- 停止命令(序号=0x13) ------->|
| |
|<------ 停止响应(序号=0x13) --------|
| |
上位机 控制板
| |
|------- 命令(序号=0x12) ---------->| (帧丢失)
| |
|----- 等待1000ms超时 -------------|
| |
|------- 命令(序号=0x12) ---------->|
| | 执行成功
|<------ 响应(序号=0x12) -----------|
| |
上位机 控制板
| |
|------- 命令(序号=0x12) ---------->| CRC校验失败
| |
|<------ 响应(状态=0x07) -----------| (返回CRC错误)
| |
|------- 重发命令(序号=0x12) ------>|
| |
|<------ 响应(状态=0x00) -----------| (成功)
| |

情况处理方式
超时无响应重发命令,最多3次,仍失败则报警
CRC校验失败丢弃该帧,等待超时后重发
序号不匹配丢弃该帧,等待正确响应
收到错误状态码根据状态码进行相应处理,记录日志
情况处理方式
帧头/帧尾错误丢弃该帧,不做响应
CRC校验失败返回状态码0x07(CRC错误)
命令码无效返回状态码0x06(无效命令)
参数超出范围返回状态码0x05(参数错误)
设备忙返回状态码0x08(设备忙)

请求帧构造:

帧头: AA 55
长度: 03 (序号1+命令1+数据3 = 5字节 - 2 = 3)
序号: 12
命令: 01
数据: 09 C4 01 (转速=0x09C4=2500, 模式=0x01)
CRC: [计算] = 对 [12 01 09 C4 01] 计算 CRC
帧尾: EE
完整帧(假设CRC=0x1234):
AA 55 03 12 01 09 C4 01 34 12 EE

响应帧:

AA 55 04 12 81 00 09 C4 01 [CRC] EE
↑ ↑ ↑ ↑
命令 成功 2500RPM 运行中

请求帧:

AA 55 04 13 02 01 07 08 00 [CRC] EE
↑ ↑
定位模式 1800(0.1度)=180度

响应帧:

AA 55 04 13 82 00 07 08 00 [CRC] EE
↑
实际停止位置

Q1: 为什么要用双字节帧头?

跳转到“Q1: 为什么要用双字节帧头?”

A: 单字节帧头容易与数据混淆。双字节 0xAA55 出现在随机数据中的概率极低(1/65536),大幅提高帧同步可靠性。

Q2: 序列号为什么不能为0?

跳转到“Q2: 序列号为什么不能为0?”

A: 0x00保留用于特殊用途(如广播或无需响应的命令)。实际通讯使用0x01~0xFF循环。

Q3: CRC计算包含哪些字段?

跳转到“Q3: CRC计算包含哪些字段?”

A: 从”序号”开始到”数据区末尾”,不包含帧头、长度、CRC本身、帧尾。

Q4: 大端序是什么意思?

跳转到“Q4: 大端序是什么意思?”

A: 高字节在前。例如转速2500(0x09C4),发送顺序为: 09 C4(不是 C4 09)

Q5: 如何处理连续发送?

跳转到“Q5: 如何处理连续发送?”

A: 每次发送需要更新序列号,等待响应或超时后才发送下一条。不建议在未收到响应时发送新命令。

Q6: 控制板重启后序列号怎么办?

跳转到“Q6: 控制板重启后序列号怎么办?”

A: 上位机序列号独立维护,无需与控制板同步。控制板只需将收到的序列号原样返回即可。

A: 允许。转速=0表示目标转速为0,电机将减速停止。

Q8: 如何兼容旧版本协议?

跳转到“Q8: 如何兼容旧版本协议?”

A: 建议通过版本协商机制。可在启动时发送版本查询命令(自定义),根据响应决定使用V1.x或V2.0协议。


测试项输入期望输出测试目的
正常启动转速=1000状态=成功基本功能
超速启动转速=20000状态=参数错误参数校验
CRC错误帧故意篡改CRC无响应或错误码校验机制
帧头错误0xAA56开头无响应帧同步
序号匹配发送序号0x20响应序号0x20序号机制
超时重传模拟丢包重发3次可靠性
连续命令快速发送5条依次正确响应并发处理

项目V1.2V2.0迁移建议
帧头0xc1~c40xAA55修改帧头识别逻辑
CRC无CRC-16添加CRC计算函数
序列号无必需添加序号管理模块
错误码3种11种扩展错误处理
字节序未定义大端序确认并统一字节序

建议升级路径:

  1. 先在测试环境验证V2.0协议
  2. 确保CRC计算正确性
  3. 逐步替换生产环境设备
  4. 保留V1.2兼容代码至少3个月

附录A: 命令码快速查询表

跳转到“附录A: 命令码快速查询表”
0x01 启动0x02 停止0x03 脉冲0x04 设速0x05 查速0x10 状态
0x81 响应0x82 响应0x83 响应0x84 响应0x85 响应0x90 响应

附录B: 状态码快速查询表

跳转到“附录B: 状态码快速查询表”
0x00 成功0x01 气缸↑0x02 气缸↓0x03 伺服超时0x04 伺服偏差
0x05 参数0x06 命令0x07 CRC0x08 忙0x09 未就绪
  1. 使用串口调试工具: 推荐 SSCOM、Serial Port Utility
  2. 开启日志: 记录所有收发数据的HEX格式
  3. 验证CRC: 使用在线CRC计算器验证: http://www.ip33.com/crc.html (选择CRC-16/MODBUS)
  4. 波形分析: 使用逻辑分析仪抓取RS232波形

文档结束


  • 2025.10.9: 发布V2.0标准化协议,完全重构帧格式

来源:CSDN 原文,首次发布于 2025-10-09。