控制板与上位机通讯协议
1. 协议概述
1.1 物理层参数
参数 | 值 |
---|---|
物理接口 | RS232 |
波特率 | 38400 bps |
数据位 | 8 |
停止位 | 2 |
校验位 | 无 |
流控制 | 无 |
1.2 协议特性
- 字节序:大端序(Big-Endian,高字节在前)
- 校验方式:CRC-16/MODBUS
- 超时时间:1000ms(上位机等待控制板响应)
- 重试次数:3次
- 序列号范围:0x01~0xFF(循环使用,0x00保留)
2. 帧格式定义
2.1 通用帧结构
┌──────┬──────┬──────┬──────┬────────┬──────┬──────┐
│ 帧头 │ 长度 │ 序号 │ 命令 │ 数据 │ CRC │ 帧尾 │
│ 2B │ 1B │ 1B │ 1B │ N字节 │ 2B │ 1B │
└──────┴──────┴──────┴──────┴────────┴──────┴──────┘0xAA55 Len SeqNo CMD Data CRC16 0xEE
2.2 字段说明
字段 | 长度 | 说明 |
---|---|---|
帧头 | 2B | 固定为 0xAA55 ,用于帧同步 |
长度 | 1B | 数据区字节数(不含帧头、长度、CRC、帧尾) |
序号 | 1B | 流水号,范围 0x01~0xFF,用于匹配请求与响应 |
命令 | 1B | 命令码,见命令码表 |
数据 | N字节 | 命令相关数据,长度由"长度"字段指定 |
CRC | 2B | CRC-16/MODBUS校验,计算范围:序号~数据区末尾 |
帧尾 | 1B | 固定为 0xEE ,用于帧结束标识 |
2.3 命令码定义
命令码 | 命令名称 | 方向 | 说明 |
---|---|---|---|
0x01 | 启动命令 | 上位机→控制板 | 启动电机运行 |
0x81 | 启动响应 | 控制板→上位机 | 启动命令执行结果 |
0x02 | 停止命令 | 上位机→控制板 | 停止电机运行 |
0x82 | 停止响应 | 控制板→上位机 | 停止命令执行结果 |
0x03 | 查找脉冲命令 | 上位机→控制板 | 伺服标定 |
0x83 | 查找脉冲响应 | 控制板→上位机 | 标定执行结果 |
0x04 | 速度设置命令 | 上位机→控制板 | 设置加减速度 |
0x84 | 速度设置响应 | 控制板→上位机 | 设置执行结果 |
0x05 | 速度查询命令 | 上位机→控制板 | 查询当前速度 |
0x85 | 速度查询响应 | 控制板→上位机 | 返回当前速度 |
0x10 | 状态查询命令 | 上位机→控制板 | 查询控制板状态 |
0x90 | 状态查询响应 | 控制板→上位机 | 返回状态信息 |
规则:响应命令码 = 请求命令码 | 0x80
3. 数据类型定义
3.1 基本类型
类型 | 字节数 | 范围 | 说明 |
---|---|---|---|
UINT8 | 1 | 0~255 | 无符号8位整数 |
UINT16 | 2 | 0~65535 | 无符号16位整数(大端序) |
UINT32 | 4 | 0~4294967295 | 无符号32位整数(大端序) |
3.2 业务参数定义
参数名称 | 类型 | 范围 | 单位 | 说明 |
---|---|---|---|---|
转速 | UINT16 | 0~10000 | RPM | 电机转速 |
角度 | UINT16 | 0~3600 | 0.1° | 停止角度,精度0.1度 |
加减速度 | UINT16 | 100~5000 | RPM/s | 加减速度,过小或过大会被限制 |
3.3 状态码定义
状态码 | 名称 | 说明 |
---|---|---|
0x00 | SUCCESS | 执行成功 |
0x01 | ERR_CYLINDER_UP | 气缸上升失败 |
0x02 | ERR_CYLINDER_DOWN | 气缸下降失败 |
0x03 | ERR_SERVO_TIMEOUT | 伺服响应超时 |
0x04 | ERR_SERVO_POSITION | 伺服位置偏差过大 |
0x05 | ERR_PARAM_RANGE | 参数超出范围 |
0x06 | ERR_INVALID_CMD | 无效命令 |
0x07 | ERR_CRC_ERROR | CRC校验错误 |
0x08 | ERR_BUSY | 设备忙,拒绝执行 |
0x09 | ERR_NOT_READY | 设备未就绪 |
0xFF | ERR_UNKNOWN | 未知错误 |
4. 命令详细说明
4.1 启动命令 (0x01/0x81)
功能:启动电机,设置目标转速
上位机 → 控制板
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x03 | 数据区3字节 |
序号 | UINT8 | 流水号 |
命令 | 0x01 | 启动命令 |
数据[0-1] | UINT16 | 目标转速(0~10000 RPM) |
数据[2] | UINT8 | 启动模式(0x01=正常启动) |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
控制板 → 上位机
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x04 | 数据区4字节 |
序号 | UINT8 | 与请求相同 |
命令 | 0x81 | 启动响应 |
数据[0] | UINT8 | 状态码 |
数据[1-2] | UINT16 | 实际转速(反馈值) |
数据[3] | UINT8 | 运行状态(0x00=停止,0x01=运行) |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
示例
请求:AA55 03 12 01 09C4 01 [CRC] EE帧头 长度 序号 命令 2500RPM 模式 校验 帧尾响应:AA55 04 12 81 00 09C4 01 [CRC] EE帧头 长度 序号 命令 成功 2500RPM 运行 校验 帧尾
4.2 停止命令 (0x02/0x82)
功能:停止电机,可选定位停止功能
上位机 → 控制板
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x04 | 数据区4字节 |
序号 | UINT8 | 流水号 |
命令 | 0x02 | 停止命令 |
数据[0] | UINT8 | 停止模式 0x00=立即停止 0x01=定位停止 |
数据[1-2] | UINT16 | 停止角度(0~3600,单位0.1°) 仅定位停止时有效 |
数据[3] | UINT8 | 保留,填0x00 |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
控制板 → 上位机
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x04 | 数据区4字节 |
序号 | UINT8 | 与请求相同 |
命令 | 0x82 | 停止响应 |
数据[0] | UINT8 | 状态码 |
数据[1-2] | UINT16 | 实际停止角度(反馈值) |
数据[3] | UINT8 | 运行状态(0x00=已停止) |
CRC | UINT16 | CRC校验值 |
帧尾 | 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)
功能:执行伺服电机Z相脉冲查找,用于系统标定
上位机 → 控制板
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x01 | 数据区1字节 |
序号 | UINT8 | 流水号 |
命令 | 0x03 | 查找脉冲命令 |
数据[0] | UINT8 | 查找模式(0x01=标准模式) |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
控制板 → 上位机
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x05 | 数据区5字节 |
序号 | UINT8 | 与请求相同 |
命令 | 0x83 | 查找脉冲响应 |
数据[0] | UINT8 | 状态码 |
数据[1-4] | UINT32 | 脉冲位置(编码器计数值) |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
示例
请求:AA55 01 15 03 01 [CRC] EE响应:AA55 05 15 83 00 00001234 [CRC] EE状态成功,脉冲位置=0x00001234
4.4 速度设置命令 (0x04/0x84)
功能:设置加减速度参数
上位机 → 控制板
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x03 | 数据区3字节 |
序号 | UINT8 | 流水号 |
命令 | 0x04 | 速度设置命令 |
数据[0-1] | UINT16 | 加减速度(100~5000 RPM/s) |
数据[2] | UINT8 | 保留,填0x00 |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
控制板 → 上位机
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x03 | 数据区3字节 |
序号 | UINT8 | 与请求相同 |
命令 | 0x84 | 速度设置响应 |
数据[0] | UINT8 | 状态码 |
数据[1-2] | UINT16 | 实际设置的速度值 |
CRC | UINT16 | CRC校验值 |
帧尾 | 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)
功能:查询当前加减速度设置
上位机 → 控制板
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x01 | 数据区1字节 |
序号 | UINT8 | 流水号 |
命令 | 0x05 | 速度查询命令 |
数据[0] | UINT8 | 保留,填0x00 |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
控制板 → 上位机
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x03 | 数据区3字节 |
序号 | UINT8 | 与请求相同 |
命令 | 0x85 | 速度查询响应 |
数据[0] | UINT8 | 状态码 |
数据[1-2] | UINT16 | 当前速度值 |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
示例
请求:AA55 01 17 05 00 [CRC] EE响应:AA55 03 17 85 00 03E8 [CRC] EE当前速度=1000 RPM/s
4.6 状态查询命令 (0x10/0x90)
功能:查询控制板当前状态(可选扩展功能)
上位机 → 控制板
字段 | 值/类型 | 说明 |
---|---|---|
帧头 | 0xAA55 | 固定 |
长度 | 0x01 | 数据区1字节 |
序号 | UINT8 | 流水号 |
命令 | 0x10 | 状态查询命令 |
数据[0] | UINT8 | 保留,填0x00 |
CRC | UINT16 | CRC校验值 |
帧尾 | 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 | 保留 |
CRC | UINT16 | CRC校验值 |
帧尾 | 0xEE | 固定 |
5. CRC-16/MODBUS 校验算法
5.1 计算范围
从 序号 字段开始,到 数据区末尾 结束(不含帧头、长度、CRC、帧尾)
5.2 算法参数
- 多项式: 0xA001(反向多项式)
- 初始值: 0xFFFF
- 结果异或值: 0x0000
- 字节序: 低字节在前
5.3 C语言参考代码
/*** @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;
}
5.4 Python参考代码
def crc16_modbus(data: bytes) -> int:"""计算CRC-16/MODBUS"""crc = 0xFFFFfor byte in data:crc ^= bytefor _ in range(8):if crc & 0x0001:crc = (crc >> 1) ^ 0xA001else:crc >>= 1return crcdef 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())
6. 通讯流程
6.1 正常流程
上位机 控制板| ||------- 启动命令(序号=0x12) ------->|| | 执行命令|<------ 启动响应(序号=0x12) --------|| || (等待操作完成) || ||------- 停止命令(序号=0x13) ------->|| ||<------ 停止响应(序号=0x13) --------|| |
6.2 超时重传流程
上位机 控制板| ||------- 命令(序号=0x12) ---------->| (帧丢失)| ||----- 等待1000ms超时 -------------|| ||------- 命令(序号=0x12) ---------->|| | 执行成功|<------ 响应(序号=0x12) -----------|| |
6.3 CRC错误处理
上位机 控制板| ||------- 命令(序号=0x12) ---------->| CRC校验失败| ||<------ 响应(状态=0x07) -----------| (返回CRC错误)| ||------- 重发命令(序号=0x12) ------>|| ||<------ 响应(状态=0x00) -----------| (成功)| |
7. 错误处理规则
7.1 上位机处理规则
情况 | 处理方式 |
---|---|
超时无响应 | 重发命令,最多3次,仍失败则报警 |
CRC校验失败 | 丢弃该帧,等待超时后重发 |
序号不匹配 | 丢弃该帧,等待正确响应 |
收到错误状态码 | 根据状态码进行相应处理,记录日志 |
7.2 控制板处理规则
情况 | 处理方式 |
---|---|
帧头/帧尾错误 | 丢弃该帧,不做响应 |
CRC校验失败 | 返回状态码0x07(CRC错误) |
命令码无效 | 返回状态码0x06(无效命令) |
参数超出范围 | 返回状态码0x05(参数错误) |
设备忙 | 返回状态码0x08(设备忙) |
8. 完整示例
8.1 启动电机到2500RPM
请求帧构造:
帧头: 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 运行中
8.2 定位停止到180度
请求帧:
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↑实际停止位置
9. 常见问题 FAQ
Q1: 为什么要用双字节帧头?
A: 单字节帧头容易与数据混淆。双字节 0xAA55
出现在随机数据中的概率极低(1/65536),大幅提高帧同步可靠性。
Q2: 序列号为什么不能为0?
A: 0x00保留用于特殊用途(如广播或无需响应的命令)。实际通讯使用0x01~0xFF循环。
Q3: CRC计算包含哪些字段?
A: 从"序号"开始到"数据区末尾",不包含帧头、长度、CRC本身、帧尾。
Q4: 大端序是什么意思?
A: 高字节在前。例如转速2500(0x09C4),发送顺序为: 09 C4
(不是 C4 09
)
Q5: 如何处理连续发送?
A: 每次发送需要更新序列号,等待响应或超时后才发送下一条。不建议在未收到响应时发送新命令。
Q6: 控制板重启后序列号怎么办?
A: 上位机序列号独立维护,无需与控制板同步。控制板只需将收到的序列号原样返回即可。
Q7: 转速为0是否允许?
A: 允许。转速=0表示目标转速为0,电机将减速停止。
Q8: 如何兼容旧版本协议?
A: 建议通过版本协商机制。可在启动时发送版本查询命令(自定义),根据响应决定使用V1.x或V2.0协议。
10. 测试用例
测试项 | 输入 | 期望输出 | 测试目的 |
---|---|---|---|
正常启动 | 转速=1000 | 状态=成功 | 基本功能 |
超速启动 | 转速=20000 | 状态=参数错误 | 参数校验 |
CRC错误帧 | 故意篡改CRC | 无响应或错误码 | 校验机制 |
帧头错误 | 0xAA56开头 | 无响应 | 帧同步 |
序号匹配 | 发送序号0x20 | 响应序号0x20 | 序号机制 |
超时重传 | 模拟丢包 | 重发3次 | 可靠性 |
连续命令 | 快速发送5条 | 依次正确响应 | 并发处理 |
11. 版本升级说明
从V1.2升级到V2.0
项目 | V1.2 | V2.0 | 迁移建议 |
---|---|---|---|
帧头 | 0xc1~c4 | 0xAA55 | 修改帧头识别逻辑 |
CRC | 无 | CRC-16 | 添加CRC计算函数 |
序列号 | 无 | 必需 | 添加序号管理模块 |
错误码 | 3种 | 11种 | 扩展错误处理 |
字节序 | 未定义 | 大端序 | 确认并统一字节序 |
建议升级路径:
- 先在测试环境验证V2.0协议
- 确保CRC计算正确性
- 逐步替换生产环境设备
- 保留V1.2兼容代码至少3个月
12. 附录
附录A: 命令码快速查询表
0x01 启动 | 0x02 停止 | 0x03 脉冲 | 0x04 设速 | 0x05 查速 | 0x10 状态 |
---|---|---|---|---|---|
0x81 响应 | 0x82 响应 | 0x83 响应 | 0x84 响应 | 0x85 响应 | 0x90 响应 |
附录B: 状态码快速查询表
0x00 成功 | 0x01 气缸↑ | 0x02 气缸↓ | 0x03 伺服超时 | 0x04 伺服偏差 |
---|---|---|---|---|
0x05 参数 | 0x06 命令 | 0x07 CRC | 0x08 忙 | 0x09 未就绪 |
附录C: 调试技巧
- 使用串口调试工具: 推荐 SSCOM、Serial Port Utility
- 开启日志: 记录所有收发数据的HEX格式
- 验证CRC: 使用在线CRC计算器验证: http://www.ip33.com/crc.html (选择CRC-16/MODBUS)
- 波形分析: 使用逻辑分析仪抓取RS232波形
文档结束
更新记录
- 2025.10.9: 发布V2.0标准化协议,完全重构帧格式