RTU添加
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user