# RS485 扩展继电器板通信协议 V1.0 > 适用:控制终端(主控,V1.7.1 起)外接级联继电器扩展板(从机)。 > 从机板硬件/固件按本文档实现即可与主控直接对接。 ## 1. 概述 主控板载 4 路继电器(sw1~sw4)不够用时,通过 RS485 总线级联一块扩展板,再扩 4 路带反馈继电器(平台标识符 sw5~sw8)。 - 主从结构:控制终端 = 主机(唯一主站),扩展板 = 从机 - 协议:**Modbus RTU**,从机地址固定 **0x10**(称重秤占用 0x01,勿冲突) - 与称重秤**共用同一条 485 总线**(主控 USART2,PA2/PA3) ## 2. 物理层 / 总线规则 | 项 | 值 | | --- | --- | | 波特率 | 9600 bps,8N1 | | 接口 | RS485 半双工 | | 帧定界 | 空闲间隔(主控侧 DMA+IDLE,≥1 帧间隙判一帧) | | **帧间隔** | **总线上任意两帧之间必须 ≥50ms**(从机 485 释放/回声沉降时间,实测踩过坑) | | 应答时限 | 从机收到完整请求后 **≤100ms** 内应答(主机 300ms 超时,补发 1 次) | | CRC | Modbus CRC16(多项式 0xA001,初值 0xFFFF),**低字节在前** | ## 3. 功能码 从机只需实现两个功能码: ### 3.1 FC05(0x05)写单线圈 —— 控制继电器 线圈地址 0~3 = 继电器 1~4(对应平台 sw5~sw8)。 **请求(8 字节)**: | 字节 | 内容 | | --- | --- | | 0 | 0x10(从机地址) | | 1 | 0x05(功能码) | | 2~3 | 线圈地址,大端:0x0000~0x0003 | | 4~5 | 0xFF 0x00 = 吸合;0x00 0x00 = 断开 | | 6~7 | CRC16 低字节、高字节 | **示例**:继电器 2 吸合 → `10 05 00 01 FF 00 DE BB` **应答**:从机执行动作后**原样回显请求帧**。回显内容与请求不一致(线圈号/通断值不符)主机判失败。 ### 3.2 FC03(0x03)读保持寄存器 —— 状态/反馈/故障/版本 固定读 0x0000 起 4 个寄存器。 **请求(8 字节)**:`10 03 00 00 00 04 47 48` **应答(13 字节)**: | 字节 | 内容 | | --- | --- | | 0 | 0x10 | | 1 | 0x03 | | 2 | 0x08(数据字节数) | | 3~4 | REG0:继电器输出状态,bit0~3 = 继电器 1~4(1=吸合) | | 5~6 | REG1:反馈状态,bit0~3(1=负载得电) | | 7~8 | REG2:故障标志,bit0~3(1=该路输出与反馈不一致持续 >1s) | | 9~10 | REG3:从机固件版本,如 0x0100 = V1.0 | | 11~12 | CRC16 低字节、高字节 | 寄存器 16 位大端;状态位放**低字节**即可,高字节填 0。 ### 3.3 异常应答 从机遇到非法功能码/地址/数据时回标准 Modbus 异常帧: `10 | (功能码 | 0x80) | 异常码 | CRC_lo | CRC_hi`(共 5 字节) 异常码:0x01 非法功能,0x02 非法地址,0x03 非法数据。 ## 4. 从机行为要求 1. **上电默认 4 路全部断开**(主控侧有断电记忆:每次离线→上线时,主控会比对 EEPROM 记忆状态与 REG0 实际状态, 不一致的回路会**逐路补发 FC05 纠正**——所以从机上线后紧跟着收到几条 FC05 属正常恢复流程,务必如实执行并回显) 2. FC05 收到并校验通过(地址/功能码/线圈范围/CRC)后**立即执行**再回显 3. 反馈输入:每路继电器配负载反馈检测(同主控板载继电器:吸合后负载得电=高)。从机自行维护 REG2 故障位:某路输出状态与反馈不一致**持续超过 1s** 置 1,恢复一致后清 0 4. 反馈采样建议 10~50ms 周期,加简单消抖(如连续 3 次一致才更新 REG1) 5. 只响应地址 0x10 的帧;**不要响应广播/其它地址**(总线上还有秤,地址 0x01) 6. 收帧间隔不足 50ms 也要能正常解析(主控保证发送间隔,从机只做鲁棒接收) ## 5. 主机行为(联调参考) 主控侧已实现(`HardWare/RELAY/ext_relay.c`): - **命令流程**:平台/蓝牙下发 → FC05 → 等回显(300ms 超时,补发 1 次)→ 延时 150ms 等触点稳定 → FC03 读状态 → 校验"输出位=目标状态 且 故障位=0" → 应答平台 OK/失败 → 上报全状态 - **周期轮询**:空闲每 2s 发一次 FC03,兼在线检测;连续 3 次无应答判离线(日志提示) - **断电记忆恢复**:扩展板状态存在主控 EEPROM(偏移 102 的 Relay_State[5],bit0~3);每次离线→上线时比对实际状态与记忆,不一致的回路逐路补发 FC05 纠正,恢复完成统一上报一次 - **离线行为**:离线期间下发命令直接回复平台 "ext relay board offline";板子恢复应答后自动上线并补一次状态上报 - 上电 3s 内不发帧(避开上电窗口) ## 6. 平台/蓝牙映射 | 项 | 映射 | | --- | --- | | MQTT 下发 | `iot.prop.set` 的 **sw5~sw8**(true/false),扩展板在线时状态大报文携带 sw5~sw8 字段 | | 平台应答 | 命令完成(含反馈校验)后回 `{"id":..,"code":0,"message":"OK"}` 或失败原因 | | 蓝牙命令 | **R5ON ~ R8OFF**(不应答平台,只执行+记日志);STATUS 显示扩展板状态 | | 平台物模型 | 需新增 4 个布尔字段 sw5~sw8 | ## 7. CRC16 参考实现(C) ```c static uint16_t crc16_modbus(const uint8_t *data, uint16_t len) { uint16_t crc = 0xFFFF; for (uint16_t i = 0; i < len; i++) { crc ^= data[i]; for (uint8_t j = 0; j < 8; j++) crc = (crc & 0x0001) ? ((crc >> 1) ^ 0xA001) : (crc >> 1); } return crc; /* 发送时低字节在前 */ } ``` ## 8. 联调检查清单 - [ ] 从机地址 0x10,9600-8N1 - [ ] FC05 回显与请求逐字节一致 - [ ] FC03 应答 13 字节,寄存器大端,状态位在低字节 - [ ] 应答延迟 ≤100ms - [ ] 上电 4 路全断 - [ ] 拔掉反馈线后操作对应继电器,REG2 对应位约 1s 后置 1 - [ ] 与秤同时挂总线:主控发帧间隔 ≥50ms,两者互不丢帧