253 lines
6.9 KiB
Markdown
253 lines
6.9 KiB
Markdown
|
|
# 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 地址映射表
|
|||
|
|
- 问题复现步骤
|