# Modbus 接口规范 ## 1. 文档用途 本文档用于指导主项目接入已完成现场实测的 24 路继电器、电压采集和电流采集设备。 配套文件: - `device-profile.json`:设备协议与通道映射的唯一权威配置。 - `appsettings.Modbus.example.json`:主项目默认配置字段示例。 - `接入验收清单.md`:开发完成后的测试和验收要求。 主项目实现时必须读取配置,不得在业务代码中硬编码从站地址、线圈、寄存器、量程、公式或通道映射。 ## 2. 实测资料与结论 本规范依据以下现场结果整理: - `结果_Modbus-接口-电流-电压对应表.txt`:逐个物理插位手动测量得到的采集页通道对应关系。 - `结果_modbus-tuner-20260618-131814.json`:调试程序于 2026-06-18 导出的已调通通讯参数。 编号含义必须严格区分: | 名称 | 含义 | |---|---| | `physicalSlot` | 机器上的物理接口位置,也是主项目业务层唯一使用的通道号,范围 1~24 | | `relayChannel` | 调试程序继电器控制页按钮号;实测与物理插位一致 | | `sourceDisplayChannel` | 调试程序采集页面上出现读数的通道号,仅保留作实测追溯 | | `registerOffset` | 在本次 24 寄存器回包数据区中的零基位置,主项目实际解析使用 | 主项目不得把 `sourceDisplayChannel` 当作物理插位,也不得直接用它计算字节偏移。 ## 3. 总线与串口参数 所有模块共用一条 RS485 总线。 | 参数 | 实测值 | |---|---| | 协议 | Modbus RTU | | 波特率 | 9600 | | 数据位 | 8 | | 校验 | None | | 停止位 | 1 | | 读取超时 | 500 ms | | 失败重试 | 2 次 | | CRC | CRC16-Modbus | | CRC 字节序 | 低字节在前 | | 地址、数量和寄存器数据 | 高字节在前 | 现场调试使用过 `COM9`,但 COM 号属于计算机本地设置。主项目应允许用户选择和保存,不得把 `COM9` 固定为设备协议的一部分。 同一串口的请求必须串行执行。不得让继电器写入、电压读取和电流读取同时向串口写帧。 ## 4. 模块地址 | 模块 | 从站地址 | |---|---:| | 继电器板 1,负责物理插位 1~8 | 1 | | 继电器板 2,负责物理插位 9~16 | 2 | | 继电器板 3,负责物理插位 17~24 | 3 | | 24 路电压采集模块 | 4 | | 24 路电流采集模块 | 5 | ## 5. 继电器控制 使用功能码 `0x05` 写单个线圈。 - 开:`0xFF00` - 关:`0x0000` - 正常响应应回显请求中的从站、功能码、线圈地址和值。 - 响应必须检查长度、从站、功能码、回显内容和 CRC。 主项目业务接口建议: ```text SetRelayAsync(int physicalSlot, bool isOn) ``` 处理流程: 1. 校验 `physicalSlot` 为 1~24。 2. 从 `device-profile.json` 的 `channels` 查找该物理插位。 3. 取得 `relay.slave` 和 `relay.coil`。 4. 构造并发送 `0x05` 帧。 5. 验证回显后才更新业务状态。 不要在未确认当前硬件是否允许的情况下自动全开 24 路。 ## 6. 电压采集 实测配置: | 参数 | 值 | |---|---| | 从站 | 4 | | 功能码 | `0x03` | | 起始寄存器 | 0 | | 寄存器数量 | 24 | | 量程 | 100 V | | 解析公式 | B | | 公式 | `实际电压 = DATA / 100` | | DATA 类型 | `UInt16` | | 每通道字节数 | 2 | | 数据字节序 | Big-Endian | 请求主体: ```text 04 03 00 00 00 18 ``` 追加 CRC16-Modbus 后发送。正常响应共 53 字节: ```text [从站1][功能码1][字节数0x30][48字节数据][CRC2] ``` ## 7. 电流采集 实测配置: | 参数 | 值 | |---|---| | 从站 | 5 | | 功能码 | `0x03` | | 起始寄存器 | 0 | | 寄存器数量 | 24 | | 量程 | 60 A | | 解析公式 | A | | 公式 | `实际电流 = DATA / 10000 × 60` | | DATA 类型 | `Int16` | | 每通道字节数 | 2 | | 数据字节序 | Big-Endian | 请求主体: ```text 05 03 00 00 00 18 ``` 这里的“带符号”按现场导出配置解释为:读取寄存器 0~23,并将每个 16 位原始值按二进制补码转换为 `Int16`。主项目不得自行把起始寄存器改成 24,也不得在映射地址上额外加 24。如后续更换硬件或重新标定,应修改配置版本并重新验收。 ## 8. 采集回包解析 电压和电流共用以下流程: 1. 检查响应最小长度。 2. 检查响应从站等于配置从站。 3. 检查功能码。若最高位为 1,按 Modbus 异常响应处理。 4. 检查字节数为 `registerCount × registerBytes`,当前应为 48。 5. 验证 CRC16-Modbus。 6. 对每个物理插位读取对应的 `registerOffset`。 7. 字节位置为: ```text position = dataStartOffset + registerOffset × channelBytes ``` 当前 `dataStartOffset=3`,`channelBytes=2`。 8. 按 Big-Endian 合成原始 16 位值。 9. 根据 `signed` 转换为 `UInt16` 或 `Int16`。 10. 根据 `formula` 和 `range` 换算工程值。 公式定义: ```text A: value = DATA / 10000.0 × range B: value = DATA / range ``` ## 9. 统一业务接口 主项目业务层只允许使用物理插位 1~24,建议公开以下抽象: ```text ConnectAsync() DisconnectAsync() SetRelayAsync(int physicalSlot, bool isOn) ReadAllVoltagesAsync() ReadAllCurrentsAsync() ReadMeasurementsAsync() ``` 一次测量结果建议包含: ```text PhysicalSlot Voltage Current VoltageRaw CurrentRaw Timestamp VoltageQuality CurrentQuality ``` `ReadMeasurementsAsync()` 应分别完成一次电压整帧读取和一次电流整帧读取,再按 `physicalSlot` 合并。不要为每个物理插位单独读取一次寄存器;每种采集模块一次读取 24 个寄存器即可。 ## 10. 配置加载与校验 程序启动时必须校验: - `schemaVersion` 是程序支持的版本。 - 物理插位恰好覆盖 1~24,不重复、不缺失。 - 继电器从站和线圈组合不重复。 - 电压、电流的 `registerOffset` 均在 `0~registerCount-1`。 - 每类采集映射不得出现重复的 `registerOffset`。 - 从站地址范围为 1~247。 - `registerBytes=2`、`channelBytes=2`。 - 公式只能是 `A` 或 `B`。 - 字节序和 CRC 类型为程序支持值。 配置错误时应阻止通讯并给出具体字段,不要静默使用代码默认值。 ## 11. 超时、重试和线程规则 - 一次请求从发送到收到完整响应视为一个事务。 - 失败后最多重试配置中的次数;当前为 2 次,即最多发送 3 次。 - CRC 错误、响应超时、从站错误、功能码错误和响应长度错误都应记录原始 HEX。 - 重试前应清理串口输入缓冲区,避免残帧与下一帧拼接。 - 串口操作使用互斥锁或单消费者队列串行化。 - 断开和应用退出时安全关闭串口。 ## 12. 主项目配置建议 建议将机器本地参数放在主项目配置,将设备协议和映射放在独立配置: ```text 主项目配置 └─ Modbus ├─ Enabled ├─ PortName ├─ DeviceProfilePath └─ PollIntervalMs device-profile.json ├─ 串口通讯默认参数 ├─ Modbus 帧规则 ├─ 模块协议 └─ 24 路权威映射 ``` `device-profile.json` 应随主程序发布并复制到输出目录。主项目可以提供配置界面修改 COM 口,但协议和通道映射只应由经过授权的维护流程更新。 ## 13. AI 编程强制要求 将本目录交给主项目 AI 时,应附加以下要求: > 严格按《Modbus接口规范.md》和 `device-profile.json` 实现。业务层统一使用 `physicalSlot` 1~24。所有从站、线圈、寄存器、量程、公式及映射从配置读取,不得硬编码。`sourceDisplayChannel` 仅用于追溯现场实测,不参与解析寻址。实现配置启动校验、串口事务串行化、CRC及响应完整校验,并按《接入验收清单.md》完成测试。