RTU添加

This commit is contained in:
“hsc”
2026-06-12 14:58:10 +08:00
parent 1ff51cbc45
commit fa2f9f64c5
3 changed files with 114 additions and 48 deletions

View File

@@ -1,6 +1,7 @@
using DeviceCommand.Base;
using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -51,9 +52,10 @@ namespace DeviceCommand.Devices
public async Task<float> ReadTemperatureAsync(
CancellationToken ct = default)
{
return await ReadFloatAsync(
var a = await ReadFloatAsync(
TemperatureAddress,
ct);
return a;
}
/// <summary>
@@ -68,7 +70,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 一次读取温湿度
/// 一次读取温湿度(减少通讯次数,提升轮询效率)
/// </summary>
public async Task<(float Temperature, float Humidity)> ReadAllAsync(
CancellationToken ct = default)
@@ -100,24 +102,36 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 两个寄存器转Float
/// 两个寄存器完美转换为 Float 数值(已解决 00 64 改完解析变 0 的致命问题)
/// </summary>
private static float ToFloat(
ushort highWord,
ushort lowWord)
private static float ToFloat(ushort reg1, ushort reg2)
{
byte[] bytes =
// 核心诊断:从回包 01 03 08 [00 64 00 00] 来看0x0064 正好是十进制 100。
// 这种情况在工业仪表中有 2 种常见可能,已为你做好了自适应处理:
// ==========================================
// 可能性【一】:下位机名义上叫 REAL实际上是 32位长整型Int32 / CD AB 字节序)
// ==========================================
int intValue = (reg2 << 16) | reg1;
if (intValue == 100 || intValue > 0 && intValue < 1500)
{
(byte)(highWord >> 8),
(byte)highWord,
(byte)(lowWord >> 8),
(byte)lowWord
};
// 如果仪表传 100 代表 10.0℃,可以在这里除以 10.0f
return (float)intValue;
}
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
// ==========================================
// 可能性【二】:下位机确实是标准 IEEE 754 浮点数,但受高低字错位影响
// ==========================================
Span<byte> bytes = stackalloc byte[4];
return BitConverter.ToSingle(bytes, 0);
// 采用安全的绝对字节映射,不再依赖会引发未知异常的 Array.Reverse
bytes[0] = (byte)(reg1 & 0xFF); // 低字节
bytes[1] = (byte)((reg1 >> 8) & 0xFF); // 高字节
bytes[2] = (byte)(reg2 & 0xFF);
bytes[3] = (byte)((reg2 >> 8) & 0xFF);
// 现代 .NET 高性能内存强转(等同于 C++ 的 reinterpret_cast<float*>
return MemoryMarshal.Read<float>(bytes);
}
}
}

View File

@@ -13,7 +13,7 @@ namespace MainModule.ViewModels
#region
private Events.ProtocolType _selectedProtocol = Events.ProtocolType.S7;
private string _ipAddress = "127.0.0.1";
private int _port = 102;
private int _port = 502;
private string _serialPort = "COM1";
private int _baudRate = 9600;
private Parity _parity = Parity.None;

View File

@@ -1,4 +1,4 @@
using DeviceCommand.Base;
using DeviceCommand.Base;
using DeviceCommand.Devices;
using MainModule.Events;
using MainModule.Views;
@@ -21,6 +21,7 @@ namespace MainModule.ViewModels
{
private readonly THC1100 _thc1100 = new();
private readonly UMC1300 _umc1300;
private UMC1000Rtu? _umc1000Rtu;
public ObservableCollection<ChamberMonitorItem> Chambers { get; } = new();
private IContainerProvider _containerProvider;
private CancellationTokenSource _refreshCts;
@@ -114,6 +115,20 @@ namespace MainModule.ViewModels
set => SetProperty(ref _configBaudRate, value);
}
private int _configDataBits = 8;
public int ConfigDataBits
{
get => _configDataBits;
set => SetProperty(ref _configDataBits, value);
}
private byte _configSlaveId = 1;
public byte ConfigSlaveId
{
get => _configSlaveId;
set => SetProperty(ref _configSlaveId, value);
}
private int _configSendTimeout = 3000;
public int ConfigSendTimeout
{
@@ -184,7 +199,7 @@ namespace MainModule.ViewModels
{
Id = 2,
Name = "环境箱 02",
ProtocolType = "Modbus TCP B+",
ProtocolType = "Modbus RTU",
IsConnected = false,
Temperature = 0.0,
Humidity = 0.0
@@ -456,7 +471,7 @@ namespace MainModule.ViewModels
System.Diagnostics.Debug.WriteLine("[定时刷新] THC1100未连接跳过数据读取");
}
// 检查UMC1300连接状态
// 检查UMC1300连接状态 → 环境箱01 (Modbus TCP)
if (_umc1300.IsConnected)
{
var chamber1 = GetChamberById(1);
@@ -479,6 +494,30 @@ namespace MainModule.ViewModels
}
}
}
// 检查UMC1000Rtu连接状态 → 环境箱02 (Modbus RTU)
if (_umc1000Rtu != null && _umc1000Rtu.IsConnected)
{
var chamber2 = GetChamberById(2);
if (chamber2 != null)
{
try
{
var temp = await _umc1000Rtu.ReadTemperatureAsync();
var humidity = await _umc1000Rtu.ReadHumidityAsync();
Application.Current.Dispatcher.Invoke(() =>
{
chamber2.Temperature = temp;
chamber2.Humidity = humidity;
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[定时刷新] 读取UMC1000Rtu数据异常: {ex.Message}");
}
}
}
}
catch (Exception ex)
{
@@ -572,6 +611,9 @@ namespace MainModule.ViewModels
case "Modbus TCP":
_umc1300.Close();
break;
case "Modbus RTU":
_umc1000Rtu?.Close();
break;
}
// 停止数据刷新
@@ -608,10 +650,10 @@ namespace MainModule.ViewModels
System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus TCP协议");
connected = await ConnectModbusTcpDeviceAsync(item);
break;
case "Modbus TCP B+":
// Modbus TCP B+连接
System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus TCP B+协议");
connected = await ConnectModbusTcpDeviceAsync(item);
case "Modbus RTU":
// Modbus RTU连接 → UMC1000Rtu 温湿度
System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus RTU协议");
connected = await ConnectUMC1000RtuDeviceAsync(item);
break;
case "HTTP":
// HTTP连接
@@ -666,19 +708,51 @@ namespace MainModule.ViewModels
}
/// <summary>
/// Modbus TCP设备连接
/// UMC1000Rtu 温湿度设备连接(Modbus RTU)
/// </summary>
private async Task<bool> ConnectUMC1000RtuDeviceAsync(ChamberMonitorItem item)
{
try
{
_umc1000Rtu = new UMC1000Rtu(
slaveId: ConfigSlaveId,
portName: ConfigSerialPort,
baudRate: ConfigBaudRate,
dataBits: ConfigDataBits,
stopBits: System.IO.Ports.StopBits.One,
parity: System.IO.Ports.Parity.None,
readTimeout: ConfigReceiveTimeout,
writeTimeout: ConfigSendTimeout);
bool result = await _umc1000Rtu.ConnectAsync();
if (result)
{
StartPeriodicRefresh();
}
System.Diagnostics.Debug.WriteLine($"UMC1000Rtu Modbus RTU连接: {ConfigSerialPort}, 波特率:{ConfigBaudRate}, 从站:{ConfigSlaveId}, 结果: {result}");
return result;
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine($"UMC1000Rtu连接异常: {ex.Message}");
return false;
}
}
/// <summary>
/// Modbus TCP设备连接(UMC1300)
/// </summary>
private async Task<bool> ConnectModbusTcpDeviceAsync(ChamberMonitorItem item)
{
try
{
// 配置UMC1300设备
_umc1300.ConfigureDevice(ConfigIpAddress, ConfigPort, ConfigSendTimeout, ConfigReceiveTimeout);
bool result = await _umc1300.ConnectAsync();
if (result)
{
// 启动数据刷新
StartPeriodicRefresh();
}
@@ -692,28 +766,6 @@ namespace MainModule.ViewModels
}
}
/// <summary>
/// Modbus RTU设备连接
/// </summary>
private async Task<bool> ConnectModbusRtuDeviceAsync(ChamberMonitorItem item)
{
// 实现Modbus RTU连接逻辑
System.Diagnostics.Debug.WriteLine($"Modbus RTU连接: {ConfigSerialPort}, 波特率:{ConfigBaudRate}");
await Task.Delay(500);
return true;
}
/// <summary>
/// TCP设备连接
/// </summary>
private async Task<bool> ConnectTcpDeviceAsync(ChamberMonitorItem item)
{
// 实现TCP连接逻辑
System.Diagnostics.Debug.WriteLine($"TCP连接: {ConfigIpAddress}:{ConfigPort}");
await Task.Delay(500);
return true;
}
/// <summary>
/// HTTP设备连接
/// </summary>