# Modbus TCP 设备集成说明 ## 概述 系统已集成 Modbus TCP 通信功能,用于与洗宠设备进行实时通信和控制。使用 NModbus 3.0.81 库实现,支持生产环境部署。 ## 配置参数 在 `ConfigurationService.cs` 中配置 Modbus TCP 连接参数: ```csharp // Modbus TCP 配置 public string ModbusIpAddress { get; set; } = "192.168.1.10"; // 设备 IP 地址 public int ModbusPort { get; set; } = 502; // Modbus TCP 端口 public byte ModbusSlaveId { get; set; } = 1; // 从站 ID public int ModbusConnectTimeoutMs { get; set; } = 5000; // 连接超时(毫秒) public int ModbusReadTimeoutMs { get; set; } = 3000; // 读写超时(毫秒) ``` ## 功能特性 ### 1. 自动连接与重连 - 系统初始化时自动连接设备 - 连接失败时自动重试 - 心跳检测(每10秒)确保连接稳定 - 连接断开时自动尝试重连 ### 2. 连接状态监控 - `IsModbusConnected` 属性实时反映连接状态 - `ConnectionStatusChanged` 事件通知连接状态变化 - 界面显示连接状态提示 ### 3. 完整的 Modbus 功能 #### 读取操作 ```csharp // 读取保持寄存器 ushort[] values = await _modbusService.ReadHoldingRegistersAsync(startAddress, count); // 读取输入寄存器 ushort[] inputs = await _modbusService.ReadInputRegistersAsync(startAddress, count); // 读取线圈状态 bool[] coils = await _modbusService.ReadCoilsAsync(startAddress, count); ``` #### 写入操作 ```csharp // 写入单个寄存器 await _modbusService.WriteSingleRegisterAsync(address, value); // 写入多个寄存器 await _modbusService.WriteMultipleRegistersAsync(startAddress, values); // 写入单个线圈 await _modbusService.WriteSingleCoilAsync(address, true); // 写入多个线圈 await _modbusService.WriteMultipleCoilsAsync(startAddress, coilStates); ``` ## 使用示例 ### 在 MainViewModel 中使用 ```csharp // 1. 读取设备温度(假设温度存储在寄存器地址 100) try { var tempData = await _modbusService.ReadHoldingRegistersAsync(100, 1); WaterTemperature = tempData[0] / 10.0; // 假设温度值需要除以10 } catch (Exception ex) { _logger.LogError("读取温度失败", ex); } // 2. 控制设备门(假设门控制在线圈地址 0) try { await _modbusService.WriteSingleCoilAsync(0, true); // 打开门 IsDoorOpen = true; } catch (Exception ex) { _logger.LogError("控制门失败", ex); } // 3. 启动洗护流程(假设控制寄存器在地址 200) try { ushort[] controlData = new ushort[] { 1, 30 }; // 启动,30分钟 await _modbusService.WriteMultipleRegistersAsync(200, controlData); } catch (Exception ex) { _logger.LogError("启动洗护失败", ex); } // 4. 读取液位传感器(假设在输入寄存器 300-302) try { var levels = await _modbusService.ReadInputRegistersAsync(300, 3); Shampoo1Level = levels[0]; Shampoo2Level = levels[1]; Shampoo3Level = levels[2]; } catch (Exception ex) { _logger.LogError("读取液位失败", ex); } ``` ## 设备地址映射示例 根据实际设备的 Modbus 地址映射表进行配置: ### 保持寄存器(读写) | 地址 | 功能 | 数据类型 | 说明 | |------|------|----------|------| | 0 | 系统状态 | UINT16 | 0=待机, 1=运行, 2=故障 | | 100 | 水温设定 | UINT16 | 单位:0.1°C | | 101 | 室温设定 | UINT16 | 单位:0.1°C | | 200 | 流程控制 | UINT16 | 0=停止, 1=启动 | | 201 | 流程时长 | UINT16 | 单位:分钟 | ### 输入寄存器(只读) | 地址 | 功能 | 数据类型 | 说明 | |------|------|----------|------| | 100 | 当前水温 | UINT16 | 单位:0.1°C | | 101 | 当前室温 | UINT16 | 单位:0.1°C | | 300 | 沐浴露1液位 | UINT16 | 0-100% | | 301 | 沐浴露2液位 | UINT16 | 0-100% | | 302 | 沐浴露3液位 | UINT16 | 0-100% | ### 线圈(读写) | 地址 | 功能 | 说明 | |------|------|------| | 0 | 门控制 | 0=关闭, 1=打开 | | 1 | 喷水阀 | 0=关闭, 1=打开 | | 2 | 热风机 | 0=关闭, 1=打开 | | 3 | 冷风机 | 0=关闭, 1=打开 | | 4 | 紫外线灯 | 0=关闭, 1=打开 | ## 错误处理 ### 连接错误 - 连接超时:检查网络连接和设备 IP 地址 - 连接被拒绝:检查设备是否启用 Modbus TCP 服务 - 设备无响应:检查从站 ID 是否正确 ### 读写错误 - 非法地址:检查寄存器地址是否在设备支持范围内 - 非法数据值:检查写入的数据是否符合设备要求 - 超时:增加 `ModbusReadTimeoutMs` 值 ## 日志记录 所有 Modbus 操作都会记录到日志系统: ``` [INFO] 正在连接 Modbus TCP 设备: 192.168.1.10:502 [INFO] Modbus TCP 连接成功: 192.168.1.10:502 [INFO] 读取保持寄存器成功: 地址=100, 数量=1 [INFO] 写入单个线圈成功: 地址=0, 值=True [ERROR] 读取保持寄存器失败: 地址=100 [WARNING] 心跳检测: 连接已断开,尝试重连... ``` ## 生产环境部署建议 ### 1. 网络配置 - 确保控制端与设备在同一网络或可路由网络 - 配置静态 IP 地址避免地址变化 - 使用专用网络隔离 Modbus 通信 ### 2. 超时设置 - 根据网络延迟调整超时参数 - 局域网环境:连接超时 3-5 秒,读写超时 1-3 秒 - 跨网段环境:适当增加超时时间 ### 3. 错误恢复 - 启用自动重连机制(已实现) - 监控连接状态并记录日志 - 设置告警通知管理员 ### 4. 性能优化 - 批量读写操作使用 `ReadMultiple` 和 `WriteMultiple` 方法 - 避免频繁的单个寄存器读写 - 合理设置心跳检测间隔 ### 5. 安全考虑 - 使用防火墙限制 Modbus TCP 端口访问 - 实施访问控制和身份验证 - 定期更新设备固件 ## 测试验证 ### 1. 连接测试 ```csharp // 测试基本连接 var connected = await _modbusService.ConnectAsync(); Assert.IsTrue(connected); Assert.IsTrue(_modbusService.IsConnected); ``` ### 2. 读写测试 ```csharp // 测试读取 var data = await _modbusService.ReadHoldingRegistersAsync(0, 1); Assert.IsNotNull(data); // 测试写入 await _modbusService.WriteSingleRegisterAsync(0, 100); var verify = await _modbusService.ReadHoldingRegistersAsync(0, 1); Assert.AreEqual(100, verify[0]); ``` ### 3. 断线重连测试 - 断开网络连接 - 观察日志中的重连尝试 - 恢复网络连接 - 验证自动重连成功 ## 故障排查 ### 问题:无法连接设备 1. 检查设备 IP 和端口是否正确 2. 使用 ping 命令测试网络连通性 3. 使用 Modbus 测试工具验证设备响应 4. 检查防火墙设置 ### 问题:连接频繁断开 1. 检查网络稳定性 2. 增加超时时间 3. 检查设备负载 4. 查看设备日志 ### 问题:读写操作失败 1. 验证寄存器地址是否正确 2. 检查从站 ID 配置 3. 确认数据格式符合设备要求 4. 查看详细错误日志 ## 技术支持 如遇到问题,请提供以下信息: - 设备型号和固件版本 - 网络拓扑结构 - 完整的错误日志 - Modbus 地址映射表 - 问题复现步骤