# Spoolold → Spoolend 移植计划 ## 一、Spoolold 功能汇总 Spoolold 是一个 **线缆卷筒末端控制器**(STM32G431),核心功能如下: | 功能模块 | 说明 | |---------|------| | **Modbus RTU 从机** | UART1, 地址 0x34, 支持 FC03/FC06/FC10, 12 个保持寄存器 | | **Modbus RTU 主机** | UART2, 向 DMK 电机驱动器发送速度/方向指令 | | **4 路继电器输出** | K1-K4 独立开关控制,由 Modbus 寄存器 [0]-[3] 驱动 | | **电源管理** | K5 继电器,支持手动/自动(超时)模式,含极性反转配置 | | **通信超时保护** | 无通信活动时自动停止电机、关闭电源 | | **DMK 电机控制** | 3 相状态机(模式→速度→方向),100ms/相,通过 Modbus FC06 发送 | | **Flash 参数持久化** | 12 个 int16_t 参数存储在 Flash 最后一页,写入 55 触发保存 | | **IWDG 看门狗** | 主循环喂狗,死机自动复位 | ### 核心数据结构:holdingRegisters[12] | 索引 | 默认值 | 功能 | |------|--------|------| | [0]-[3] | 50 | K1-K4 继电器控制(0=关, 非0=开)| | [4] | 0 | 电源极性(0=正逻辑, 非0=反转)| | [5] | 0 | 电源模式(0=自动超时, 非0=手动)| | [6] | 0 | 手动电源开关(0=关, 非0=开)| | [7] | 0 | 通信超时阈值(ms) | | [8] | 2000 | 电机速度 | | [9] | 0 | 电机状态(0=停, 1=正转, 2=反转)| | [10] | 0 | Flash 保存触发(55=保存)| | [11] | 0 | 保留 | --- ## 二、新旧架构对比 | 维度 | Spoolold (旧) | Spoolend (新) | |------|--------------|---------------| | UART 驱动 | 直接调 HAL,逐字节中断接收 | `bsp_uart.h` + `TComCtrl` 抽象层,环形缓冲区 | | Modbus 协议 | 自带 `modbus.c`(从机+主机)| 无,需移植 | | 电机控制 | 自带 `dmk.c`(3 相状态机)| 无,需移植 | | Flash 操作 | 自带 `flash_operation.c`(直接操作 Flash)| 可用 `bspMCU/stmflash.h` | | GPIO 控制 | 直接 HAL_GPIO_WritePin | 同样方式,无需改变 | | 发送方式 | DMA 发送 | `TComCtrl` 的 `rd_ComSendProc` + 自定义 send 回调 | --- ## 三、移植方案 ### 3.1 文件结构规划 在 `robot/project/Spoolend/` 下新增: ``` Spoolend/ ├── CMakeLists.txt (已有,需更新源文件列表) ├── Spoolend.c (已有,需重写) ├── include/ │ ├── Spoolend.h (新建 - 公共接口) │ ├── modbus.h (从 Spoolold 移植,适配 TComCtrl) │ ├── dmk.h (从 Spoolold 移植) │ └── flash_operation.h (从 Spoolold 移植,适配 stmflash) ├── modbus.c (从 Spoolold 移植,重写收发层) ├── dmk.c (从 Spoolold 移植,适配新 Modbus 接口) └── flash_operation.c (从 Spoolold 移植,适配 stmflash API) ``` ### 3.2 各模块移植要点 #### A. Modbus 协议栈 (`modbus.c/h`) **保留:** - CRC-16 计算逻辑 - FC03/FC06/FC10 帧解析与响应构造 - 异常响应机制 - 寄存器读写逻辑 + 可写性检查 **重写:** - **接收层**:不再逐字节中断接收,改为通过 `TComCtrl` 的 `check`/`decode` 回调机制 - `check_RS485_1()` → 做 Modbus 帧完整性校验(CRC + 长度),返回帧长或 0 - `decode_RS485_1()` → 调用 `Modbus_Process()` 解析帧内容 - **发送层**:`Modbus_SendResponse()` 改为调用 `rd_ComWrite(g_ptRS485_1, ...)` - **主机发送**:`Modbus_Master_Send()` 改为调用 `rd_ComWrite(g_ptRS485_2, ...)` - **超时检测**:不再依赖 `Rx_Pre_time`,改用 `TComCtrl` 的 `m_uiLastRecvTime` **关键适配:** ```c // 旧:HAL_UART_Transmit_DMA(&huart1, data, len) // 新:rd_ComWrite(g_ptRS485_1, (char*)data, len) // 旧:逐字节 HAL_UART_Receive_IT + HAL_UART_RxCpltCallback // 新:check 回调做帧校验,decode 回调做帧处理 ``` #### B. DMK 电机控制 (`dmk.c/h`) **保留:** - 3 相状态机逻辑(模式→速度→方向,100ms/相) - 电机方向映射(0=停, 1=正转→0x01, 2=反转→0x14) **重写:** - `MB_WriteHoldingReg()` 调用改为新的 Modbus 主机接口 - 超时检测逻辑适配 `TComCtrl` 时间戳 #### C. Flash 参数存储 (`flash_operation.c/h`) **方案选择:** 使用 `bspMCU/stmflash.h` 提供的 API **适配:** ```c // 旧:直接 HAL_FLASH_Unlock / HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, ...) // 新:STMFLASH_Write(WriteAddr, pBuffer, NumToWrite) // STMFLASH_Read(ReadAddr, pBuffer, NumToRead) // STMFLASH_EraseByAddress(Address) ``` 注意:`stmflash.h` 有 `#ifdef USE_ONCHIP_FLASH` 保护,需确保 CMake 中启用该宏。 #### D. 主逻辑 (`Spoolend.c`) **SpoolendInit():** 1. 初始化 RS485_1(已有)→ 绑定 Modbus 从机 check/decode 2. 初始化 RS485_2(已有)→ 绑定 Modbus 主机 send 3. 初始化 FDCAN1(保留,可选) 4. 调用 `Flash_ReadParameters()` 恢复参数 5. 设置 holdingRegisters[8] = 2000(默认速度) 6. IWDG 初始化(如 CubeMX 未配置) **SpoolendTask():** 1. `HAL_IWDG_Refresh()` 喂狗 2. `rd_ComRead` + `Modbus_Process()` 处理 Modbus 帧 3. K1-K4 GPIO 控制(holdingRegisters[0..3]) 4. 通信超时判断 + 电机停止 5. `handle_dmk_motor()` 电机控制 6. `handle_power_on_off()` 电源管理 7. Flash 保存检查(holdingRegisters[10]==55) 8. `rd_ComSendProc()` 发送处理 ### 3.3 CMakeLists.txt 更新 ```cmake set(SRC_LIST Spoolend.c modbus.c dmk.c flash_operation.c ) ``` 依赖关系保持不变:`target_link_libraries(${TARGET_NAME} PUBLIC bspMCU)` --- ## 四、移植顺序 1. **flash_operation.c/h** → 最独立,先移植并验证 Flash 读写 2. **modbus.c/h** → 核心协议,移植从机部分先(FC03/06/10),再移植主机部分 3. **dmk.c/h** → 依赖 Modbus 主机接口 4. **Spoolend.c** → 整合所有模块,替换 demo 逻辑为正式控制逻辑 --- ## 五、验证方案 1. **Flash 验证**:写入参数 → 重启 → 读取比对 2. **Modbus 从机验证**:用 Modbus Poll 等工具连接 RS485_1,读写 12 个寄存器 3. **Modbus 主机验证**:连接 DMK 驱动器,发送速度/方向命令,观察响应 4. **GPIO 验证**:通过 Modbus 写 K1-K4 寄存器,用万用表测引脚电平 5. **电源管理验证**:设置超时阈值,断开通信,观察 K5 自动关闭 6. **看门狗验证**:故意死循环,观察系统自动复位 --- ## 六、关键文件路径 | 文件 | 路径 | |------|------| | Spoolold 主逻辑 | `robot/project_old/Spoolold/Spoolold.c` | | Modbus 旧实现 | `robot/project_old/Spoolold/modbus.c` | | DMK 旧实现 | `robot/project_old/Spoolold/dmk.c` | | Flash 旧实现 | `robot/project_old/Spoolold/flash_operation.c` | | Spoolend 当前代码 | `robot/project/Spoolend/Spoolend.c` | | TComCtrl 通信抽象 | `robot/peripheral/include/com.h` | | BSP UART 驱动 | `robot/bspMCU/include/bsp_uart.h` | | BSP Flash 驱动 | `robot/bspMCU/include/stmflash.h` | | 根 CMakeLists | `robot/CMakeLists.txt` | # Spoolend 线轴端控制板 — 测试用例文档 ## 一、测试环境 | 项目 | 说明 | |------|------| | 硬件 | STM32G431 控制板 + DMK 电机驱动器 + 5路继电器模块 | | 上位机工具 | Modbus Poll / Modbus Slave / 自定义串口工具 | | 连接 | RS485_1 (USART1) → 上位机主机, RS485_2 (USART3) → DMK 驱动器 | | 波特率 | 115200, 8N1 | | Modbus 从机地址 | 0x34 (52) | --- ## 二、Modbus 从机通信测试 ### TC-MODBUS-01: FC03 读保持寄存器 — 正常读取全部寄存器 | 项目 | 内容 | |------|------| | 前置条件 | 系统正常启动 | | 操作 | 发送: `34 03 0000 000C CRC` | | 预期响应 | `34 03 18 [24字节寄存器数据] CRC` | | 验证点 | 返回 12 个寄存器值,与 holdingRegisters[0..11] 一致 | ### TC-MODBUS-02: FC03 读保持寄存器 — 读取单个寄存器 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 03 0000 0001 CRC` (读 K1 状态) | | 预期响应 | `34 03 02 [K1值高] [K1值低] CRC` | ### TC-MODBUS-03: FC03 读保持寄存器 — 地址越界 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 03 000B 0002 CRC` (从地址11开始读2个) | | 预期响应 | `34 83 02 CRC` (异常码 0x02: 非法数据地址) | ### TC-MODBUS-04: FC06 写单个寄存器 — 写 K1 控制 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 06 0000 0000 CRC` (K1 设为 0) | | 预期响应 | `34 06 0000 0000 CRC` (原帧回显) | | 验证点 | K1 引脚变为低电平;再发 `34 06 0000 0001 CRC`,K1 恢复高电平 | ### TC-MODBUS-05: FC06 写单个寄存器 — 地址越界 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 06 000C 0000 CRC` (地址 12 超出范围) | | 预期响应 | `34 86 02 CRC` (异常码 0x02) | ### TC-MODBUS-06: FC10 写多个寄存器 — 批量写入 K1-K4 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 10 0000 0004 08 0001 0000 0001 0000 CRC` | | 预期响应 | `34 10 0000 0004 CRC` | | 验证点 | K1=1, K2=0, K3=1, K4=0;GPIO 引脚电平对应变化 | ### TC-MODBUS-07: FC10 写多个寄存器 — 数据长度错误 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 10 0000 0004 04 0001 0000 CRC` (byteCount=4 但 registerCount=4 需要 8 字节) | | 预期响应 | `34 90 03 CRC` (异常码 0x03) | ### TC-MODBUS-08: FC10 写多个寄存器 — 只读寄存器保护 | 项目 | 内容 | |------|------| | 前置条件 | registerWritable[i] = 0 的寄存器 | | 操作 | 尝试写入只读寄存器 | | 预期响应 | 正常响应,但只读寄存器值不变 | ### TC-MODBUS-09: CRC 校验 — 错误 CRC | 项目 | 内容 | |------|------| | 操作 | 发送: `34 03 0000 0001 0000` (CRC 错误) | | 预期响应 | 无响应(静默丢弃) | ### TC-MODBUS-10: 不支持的功能码 | 项目 | 内容 | |------|------| | 操作 | 发送: `34 01 0000 0001 CRC` (FC01 不支持) | | 预期响应 | `34 81 01 CRC` (异常码 0x01) | --- ## 三、GPIO 继电器控制测试 ### TC-GPIO-01: K1-K4 独立控制 | 项目 | 内容 | |------|------| | 操作 | 通过 FC06 依次写 holdingRegisters[0..3] 为非零值 | | 预期 | K1→K4 引脚依次变为高电平 (GPIO_PIN_SET) | | 操作 | 写为 0 | | 预期 | K1→K4 引脚依次变为低电平 (GPIO_PIN_RESET) | ### TC-GPIO-02: K1-K4 默认状态 | 项目 | 内容 | |------|------| | 操作 | 系统上电,不发送任何 Modbus 命令 | | 预期 | holdingRegisters[0..3] 默认值为 50 (0x32),K1-K4 均为高电平 | ### TC-GPIO-03: LED1 指示灯 | 项目 | 内容 | |------|------| | 操作 | 发送任意 Modbus 命令到本机地址 (0x34) | | 预期 | LED1 翻转一次 | --- ## 四、电源管理测试 (K5) ### TC-PWR-01: 自动模式 — 通信正常时电源开启 | 项目 | 内容 | |------|------| | 前置条件 | holdingRegisters[5]=0 (自动), [4]=0 (正极性), [7]=5000 (5秒超时) | | 操作 | 持续发送 Modbus 命令(间隔 < 5秒) | | 预期 | K5 引脚保持低电平(电源开启,正极性时 RESET=开) | ### TC-PWR-02: 自动模式 — 通信超时关闭电源 | 项目 | 内容 | |------|------| | 前置条件 | 同上 | | 操作 | 停止发送 Modbus 命令,等待超过 5 秒 | | 预期 | K5 引脚变为高电平(电源关闭) | ### TC-PWR-03: 自动模式 — 通信恢复重新开启 | 项目 | 内容 | |------|------| | 操作 | 超时后重新发送 Modbus 命令 | | 预期 | K5 引脚恢复低电平(电源重新开启) | ### TC-PWR-04: 手动模式 — 开启电源 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[5]=1 (手动), [6]=1 (开) | | 预期 | K5 引脚变为低电平(电源开启) | ### TC-PWR-05: 手动模式 — 关闭电源 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[6]=0 (关) | | 预期 | K5 引脚变为高电平(电源关闭) | ### TC-PWR-06: 极性反转 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[4]=1 (反极性) | | 预期 | K5 引脚电平逻辑反转(SET=关, RESET=开) | --- ## 五、DMK 电机控制测试 ### TC-DMK-01: 电机正转 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[9]=1 (正转), [8]=2000 (速度) | | 预期 | RS485_2 周期性 (300ms) 向 DMK 发送: 模式→速度→方向(0x01) | | 验证点 | 用串口监听 RS485_2,确认 3 相 Modbus FC06 帧正确 | ### TC-DMK-02: 电机反转 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[9]=2 | | 预期 | 方向寄存器 0x033 写入值 0x14 | ### TC-DMK-03: 电机停止 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[9]=0 | | 预期 | 方向寄存器 0x033 写入值 0x00 | ### TC-DMK-04: 速度设置 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[8]=3000 | | 预期 | 速度寄存器 0x06A 写入值 3000 | ### TC-DMK-05: 3 相时序验证 | 项目 | 内容 | |------|------| | 操作 | 电机运行中,监听 RS485_2 输出 | | 预期 | 每 300ms 周期: 相0(0-100ms)写模式=0, 相1(100-200ms)写速度, 相2(200-300ms)写方向 | ### TC-DMK-06: 默认速度 | 项目 | 内容 | |------|------| | 操作 | 系统上电 | | 预期 | holdingRegisters[8] 硬编码为 2000(即使 Flash 中存储了其他值) | --- ## 六、通信超时保护测试 ### TC-TIMEOUT-01: 超时停止电机 | 项目 | 内容 | |------|------| | 前置条件 | holdingRegisters[7]=5000, 电机正在运行 | | 操作 | 停止 Modbus 通信超过 5 秒 | | 预期 | RS485_2 发送停止命令 `MB_WriteHoldingReg(1, 0x33, 0x0)` | ### TC-TIMEOUT-02: 超时阈值为 0 时禁用超时 | 项目 | 内容 | |------|------| | 操作 | FC06 写 holdingRegisters[7]=0 | | 预期 | 通信超时不会触发停止(阈值为 0 时立即超时,但需验证行为) | --- ## 七、Flash 参数持久化测试 ### TC-FLASH-01: 参数保存 | 项目 | 内容 | |------|------| | 操作 | 修改 K1-K4 为自定义值,FC06 写 holdingRegisters[10]=55 | | 预期 | 参数写入 Flash 最后一页;holdingRegisters[10] 自动变为 1 | | 验证 | 发送 FC03 读取确认 [10]=1 | ### TC-FLASH-02: 参数恢复 | 项目 | 内容 | |------|------| | 前置条件 | TC-FLASH-01 已执行 | | 操作 | 系统复位/重新上电 | | 预期 | 从 Flash 读取参数,K1-K4 恢复为保存时的值 | ### TC-FLASH-03: 保存后速度覆盖 | 项目 | 内容 | |------|------| | 操作 | 保存时 holdingRegisters[8]=3000,重启 | | 预期 | Flash 读取后 [8]=3000,但 SpoolendInit 硬编码覆盖为 2000 | ### TC-FLASH-04: 默认参数 | 项目 | 内容 | |------|------| | 操作 | 全新芯片首次启动(Flash 为空白 0xFF) | | 预期 | holdingRegisters[0..3] 读取为 0xFFFF (非零=开),K1-K4 默认开启 | --- ## 八、看门狗测试 ### TC-WDG-01: 正常运行不复位 | 项目 | 内容 | |------|------| | 操作 | 系统正常运行 | | 预期 | SpoolendTask 每次循环喂狗,系统持续运行不复位 | ### TC-WDG-02: 死机自动复位 | 项目 | 内容 | |------|------| | 操作 | 在 SpoolendTask 中插入 `while(1);` 死循环 | | 预期 | IWDG 超时后系统自动复位 | --- ## 九、FDCAN 测试 ### TC-CAN-01: CAN 数据透传 | 项目 | 内容 | |------|------| | 操作 | 向 FDCAN1 发送任意 CAN 帧 | | 预期 | 数据通过 rd_ComIDWrite 回传(echo) | ### TC-CAN-02: CAN 错误恢复 | 项目 | 内容 | |------|------| | 操作 | 制造 CAN 总线错误 | | 预期 | HAL_FDCAN_ErrorStatusCallback 触发 MX_FDCAN1_Init 重新初始化 | --- ## 十、边界条件与异常测试 ### TC-EDGE-01: Modbus 帧不完整 | 项目 | 内容 | |------|------| | 操作 | 发送不完整的 Modbus 帧(如只有地址字节 `34`) | | 预期 | 等待后续数据或超时丢弃,不崩溃 | ### TC-EDGE-02: 非本机地址帧 | 项目 | 内容 | |------|------| | 操作 | 发送地址非 0x34 的 Modbus 帧 | | 预期 | 静默忽略,不响应 | ### TC-EDGE-03: 高频 Modbus 请求 | 项目 | 内容 | |------|------| | 操作 | 以最大频率连续发送 FC03 读取请求 | | 预期 | 每帧正确响应,不丢帧不乱序 | ### TC-EDGE-04: 同时读写寄存器 | 项目 | 内容 | |------|------| | 操作 | 一边用 FC03 读取,一边用 FC06 写入 | | 预期 | 读取返回写入前或写入后的值(无中间态撕裂) | --- ## 十一、测试用例统计 | 类别 | 用例数 | |------|--------| | Modbus 从机通信 | 10 | | GPIO 继电器控制 | 3 | | 电源管理 | 6 | | DMK 电机控制 | 6 | | 通信超时保护 | 2 | | Flash 参数持久化 | 4 | | 看门狗 | 2 | | FDCAN | 2 | | 边界与异常 | 4 | | **合计** | **39** |