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 DeviceCommand.Base;
using System; using System;
using System.IO.Ports; using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -51,9 +52,10 @@ namespace DeviceCommand.Devices
public async Task<float> ReadTemperatureAsync( public async Task<float> ReadTemperatureAsync(
CancellationToken ct = default) CancellationToken ct = default)
{ {
return await ReadFloatAsync( var a = await ReadFloatAsync(
TemperatureAddress, TemperatureAddress,
ct); ct);
return a;
} }
/// <summary> /// <summary>
@@ -68,7 +70,7 @@ namespace DeviceCommand.Devices
} }
/// <summary> /// <summary>
/// 一次读取温湿度 /// 一次读取温湿度(减少通讯次数,提升轮询效率)
/// </summary> /// </summary>
public async Task<(float Temperature, float Humidity)> ReadAllAsync( public async Task<(float Temperature, float Humidity)> ReadAllAsync(
CancellationToken ct = default) CancellationToken ct = default)
@@ -100,24 +102,36 @@ namespace DeviceCommand.Devices
} }
/// <summary> /// <summary>
/// 两个寄存器转Float /// 两个寄存器完美转换为 Float 数值(已解决 00 64 改完解析变 0 的致命问题)
/// </summary> /// </summary>
private static float ToFloat( private static float ToFloat(ushort reg1, ushort reg2)
ushort highWord,
ushort lowWord)
{ {
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), // 如果仪表传 100 代表 10.0℃,可以在这里除以 10.0f
(byte)highWord, return (float)intValue;
(byte)(lowWord >> 8), }
(byte)lowWord
};
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 #region
private Events.ProtocolType _selectedProtocol = Events.ProtocolType.S7; private Events.ProtocolType _selectedProtocol = Events.ProtocolType.S7;
private string _ipAddress = "127.0.0.1"; private string _ipAddress = "127.0.0.1";
private int _port = 102; private int _port = 502;
private string _serialPort = "COM1"; private string _serialPort = "COM1";
private int _baudRate = 9600; private int _baudRate = 9600;
private Parity _parity = Parity.None; private Parity _parity = Parity.None;

View File

@@ -1,4 +1,4 @@
using DeviceCommand.Base; using DeviceCommand.Base;
using DeviceCommand.Devices; using DeviceCommand.Devices;
using MainModule.Events; using MainModule.Events;
using MainModule.Views; using MainModule.Views;
@@ -21,6 +21,7 @@ namespace MainModule.ViewModels
{ {
private readonly THC1100 _thc1100 = new(); private readonly THC1100 _thc1100 = new();
private readonly UMC1300 _umc1300; private readonly UMC1300 _umc1300;
private UMC1000Rtu? _umc1000Rtu;
public ObservableCollection<ChamberMonitorItem> Chambers { get; } = new(); public ObservableCollection<ChamberMonitorItem> Chambers { get; } = new();
private IContainerProvider _containerProvider; private IContainerProvider _containerProvider;
private CancellationTokenSource _refreshCts; private CancellationTokenSource _refreshCts;
@@ -114,6 +115,20 @@ namespace MainModule.ViewModels
set => SetProperty(ref _configBaudRate, value); 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; private int _configSendTimeout = 3000;
public int ConfigSendTimeout public int ConfigSendTimeout
{ {
@@ -184,7 +199,7 @@ namespace MainModule.ViewModels
{ {
Id = 2, Id = 2,
Name = "环境箱 02", Name = "环境箱 02",
ProtocolType = "Modbus TCP B+", ProtocolType = "Modbus RTU",
IsConnected = false, IsConnected = false,
Temperature = 0.0, Temperature = 0.0,
Humidity = 0.0 Humidity = 0.0
@@ -456,7 +471,7 @@ namespace MainModule.ViewModels
System.Diagnostics.Debug.WriteLine("[定时刷新] THC1100未连接跳过数据读取"); System.Diagnostics.Debug.WriteLine("[定时刷新] THC1100未连接跳过数据读取");
} }
// 检查UMC1300连接状态 // 检查UMC1300连接状态 → 环境箱01 (Modbus TCP)
if (_umc1300.IsConnected) if (_umc1300.IsConnected)
{ {
var chamber1 = GetChamberById(1); 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) catch (Exception ex)
{ {
@@ -572,6 +611,9 @@ namespace MainModule.ViewModels
case "Modbus TCP": case "Modbus TCP":
_umc1300.Close(); _umc1300.Close();
break; break;
case "Modbus RTU":
_umc1000Rtu?.Close();
break;
} }
// 停止数据刷新 // 停止数据刷新
@@ -608,10 +650,10 @@ namespace MainModule.ViewModels
System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus TCP协议"); System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus TCP协议");
connected = await ConnectModbusTcpDeviceAsync(item); connected = await ConnectModbusTcpDeviceAsync(item);
break; break;
case "Modbus TCP B+": case "Modbus RTU":
// Modbus TCP B+连接 // Modbus RTU连接 → UMC1000Rtu 温湿度
System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus TCP B+协议"); System.Diagnostics.Debug.WriteLine("[连接] 使用设备配置的Modbus RTU协议");
connected = await ConnectModbusTcpDeviceAsync(item); connected = await ConnectUMC1000RtuDeviceAsync(item);
break; break;
case "HTTP": case "HTTP":
// HTTP连接 // HTTP连接
@@ -666,19 +708,51 @@ namespace MainModule.ViewModels
} }
/// <summary> /// <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> /// </summary>
private async Task<bool> ConnectModbusTcpDeviceAsync(ChamberMonitorItem item) private async Task<bool> ConnectModbusTcpDeviceAsync(ChamberMonitorItem item)
{ {
try try
{ {
// 配置UMC1300设备
_umc1300.ConfigureDevice(ConfigIpAddress, ConfigPort, ConfigSendTimeout, ConfigReceiveTimeout); _umc1300.ConfigureDevice(ConfigIpAddress, ConfigPort, ConfigSendTimeout, ConfigReceiveTimeout);
bool result = await _umc1300.ConnectAsync(); bool result = await _umc1300.ConnectAsync();
if (result) if (result)
{ {
// 启动数据刷新
StartPeriodicRefresh(); 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> /// <summary>
/// HTTP设备连接 /// HTTP设备连接
/// </summary> /// </summary>