更新20260518
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
public string IpAddress { get; set; }
|
public string IpAddress { get; set; }
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
public byte SlaveId { get; set; }
|
public byte SlaveId { get; set; }
|
||||||
|
public PlcFloatWordOrder FloatWordOrder { get; set; } = PlcFloatWordOrder.LowWordFirst;
|
||||||
|
|
||||||
// 硬度
|
// 硬度
|
||||||
public ushort HardnessMax { get; set; }
|
public ushort HardnessMax { get; set; }
|
||||||
@@ -14,7 +15,8 @@
|
|||||||
|
|
||||||
public ushort HardnessSudu { get; set; }
|
public ushort HardnessSudu { get; set; }
|
||||||
public ushort HardnessWeiyi { get; set; }
|
public ushort HardnessWeiyi { get; set; }
|
||||||
|
public ushort HardnessLimit { get; set; }
|
||||||
|
|
||||||
public ushort HardnessForward { get; set; }
|
public ushort HardnessForward { get; set; }
|
||||||
public ushort HardnessBack { get; set; }
|
public ushort HardnessBack { get; set; }
|
||||||
|
|
||||||
@@ -67,4 +69,10 @@
|
|||||||
public ushort Dissolution1SampleInterval { get; set; }
|
public ushort Dissolution1SampleInterval { get; set; }
|
||||||
public ushort Dissolution2SampleInterval { get; set; }
|
public ushort Dissolution2SampleInterval { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum PlcFloatWordOrder
|
||||||
|
{
|
||||||
|
LowWordFirst,
|
||||||
|
HighWordFirst
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace TabletTester2025.Services
|
|||||||
|
|
||||||
private readonly PlcConfiguration _config;
|
private readonly PlcConfiguration _config;
|
||||||
private readonly SemaphoreSlim _connectLock = new(1, 1);
|
private readonly SemaphoreSlim _connectLock = new(1, 1);
|
||||||
|
private readonly SemaphoreSlim _ioLock = new(1, 1);
|
||||||
private TcpClient? _tcpClient;
|
private TcpClient? _tcpClient;
|
||||||
private IModbusMaster? _master;
|
private IModbusMaster? _master;
|
||||||
|
|
||||||
@@ -149,10 +150,11 @@ namespace TabletTester2025.Services
|
|||||||
|
|
||||||
private async Task<T> ExecuteAsync<T>(Func<IModbusMaster, Task<T>> action)
|
private async Task<T> ExecuteAsync<T>(Func<IModbusMaster, Task<T>> action)
|
||||||
{
|
{
|
||||||
await EnsureConnectedAsync();
|
await _ioLock.WaitAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
await EnsureConnectedAsync();
|
||||||
|
|
||||||
if (_master == null)
|
if (_master == null)
|
||||||
throw new InvalidOperationException("PLC连接未初始化");
|
throw new InvalidOperationException("PLC连接未初始化");
|
||||||
|
|
||||||
@@ -163,9 +165,20 @@ namespace TabletTester2025.Services
|
|||||||
CloseConnection();
|
CloseConnection();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_ioLock.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float RegistersToFloat(ushort highWord, ushort lowWord)
|
private float RegistersToFloat(ushort firstRegister, ushort secondRegister)
|
||||||
|
{
|
||||||
|
return _config.FloatWordOrder == PlcFloatWordOrder.HighWordFirst
|
||||||
|
? WordsToFloat(firstRegister, secondRegister)
|
||||||
|
: WordsToFloat(secondRegister, firstRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float WordsToFloat(ushort highWord, ushort lowWord)
|
||||||
{
|
{
|
||||||
byte[] bytes =
|
byte[] bytes =
|
||||||
{
|
{
|
||||||
@@ -177,14 +190,15 @@ namespace TabletTester2025.Services
|
|||||||
return BitConverter.ToSingle(bytes, 0);
|
return BitConverter.ToSingle(bytes, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ushort[] FloatToRegisters(float value)
|
private ushort[] FloatToRegisters(float value)
|
||||||
{
|
{
|
||||||
byte[] bytes = BitConverter.GetBytes(value);
|
byte[] bytes = BitConverter.GetBytes(value);
|
||||||
return new[]
|
ushort highWord = (ushort)((bytes[3] << 8) | bytes[2]);
|
||||||
{
|
ushort lowWord = (ushort)((bytes[1] << 8) | bytes[0]);
|
||||||
(ushort)((bytes[3] << 8) | bytes[2]),
|
|
||||||
(ushort)((bytes[1] << 8) | bytes[0])
|
return _config.FloatWordOrder == PlcFloatWordOrder.HighWordFirst
|
||||||
};
|
? new[] { highWord, lowWord }
|
||||||
|
: new[] { lowWord, highWord };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseConnection()
|
private void CloseConnection()
|
||||||
@@ -200,6 +214,7 @@ namespace TabletTester2025.Services
|
|||||||
{
|
{
|
||||||
CloseConnection();
|
CloseConnection();
|
||||||
_connectLock.Dispose();
|
_connectLock.Dispose();
|
||||||
|
_ioLock.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace TabletTester2025.ViewModels
|
|||||||
ShowDataCommand = new AsyncRelayCommand(async () =>
|
ShowDataCommand = new AsyncRelayCommand(async () =>
|
||||||
{
|
{
|
||||||
// 用你项目里已有的PLC实例(假设叫 _plcClient)
|
// 用你项目里已有的PLC实例(假设叫 _plcClient)
|
||||||
var window = new ShowData(_plc);
|
var window = new ShowData(_plc, _plcConfig);
|
||||||
window.Owner = Application.Current.MainWindow;
|
window.Owner = Application.Current.MainWindow;
|
||||||
window.ShowDialog();
|
window.ShowDialog();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,37 +1,39 @@
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Sunny.UI;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using TabletTester2025.Helpers;
|
using TabletTester2025.Helpers;
|
||||||
|
using TabletTester2025.Models;
|
||||||
using TabletTester2025.Services;
|
using TabletTester2025.Services;
|
||||||
using static OfficeOpenXml.ExcelErrorValue;
|
|
||||||
|
|
||||||
namespace 片剂四用仪.Views
|
namespace 片剂四用仪.Views
|
||||||
{
|
{
|
||||||
public partial class ShowData : Window
|
public partial class ShowData : Window
|
||||||
{
|
{
|
||||||
private readonly IPlcService _plc;
|
private readonly IPlcService _plc;
|
||||||
private CancellationTokenSource _cts;
|
private readonly PlcParamMapping[] _paramMappings;
|
||||||
|
private CancellationTokenSource? _cts;
|
||||||
|
|
||||||
public ShowData(IPlcService plc)
|
public ShowData(IPlcService plc, PlcConfiguration plcConfig)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_plc = plc;
|
_plc = plc;
|
||||||
|
_paramMappings = BuildParamMappings(plcConfig);
|
||||||
Loaded += ShowData_Loaded;
|
Loaded += ShowData_Loaded;
|
||||||
Closing += ShowData_Closing;
|
Closing += ShowData_Closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ShowData_Loaded(object sender, RoutedEventArgs e)
|
private async void ShowData_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
_cts = cts;
|
||||||
BindAllTextBoxWriteEvents();
|
BindAllTextBoxWriteEvents();
|
||||||
await StartPlcReadLoop(_cts.Token);
|
await StartPlcReadLoop(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowData_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
private void ShowData_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
|
||||||
{
|
{
|
||||||
_cts?.Cancel();
|
_cts?.Cancel();
|
||||||
}
|
}
|
||||||
@@ -135,37 +137,51 @@ namespace 片剂四用仪.Views
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ====================== 地址映射表 ======================
|
// ====================== 地址映射表 ======================
|
||||||
private readonly PlcParamMapping[] _paramMappings = new[]
|
private static PlcParamMapping[] BuildParamMappings(PlcConfiguration plcConfig)
|
||||||
{
|
{
|
||||||
new PlcParamMapping("txt_HardnessSpeed", 300, PlcParamType.Float),
|
return new[]
|
||||||
new PlcParamMapping("txt_HardnessDisplacement", 310, PlcParamType.Float),
|
{
|
||||||
new PlcParamMapping("txt_HardnessMotorLimit", 298, PlcParamType.Float),
|
new PlcParamMapping("txt_HardnessSpeed", AddressOrDefault(plcConfig.HardnessSudu, 300), PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_HardnessDamageThreshold", 400, PlcParamType.Float),
|
new PlcParamMapping("txt_HardnessDisplacement", AddressOrDefault(plcConfig.HardnessWeiyi, 310), PlcParamType.Float),
|
||||||
|
new PlcParamMapping("txt_HardnessMotorLimit", AddressOrDefault(plcConfig.HardnessLimit, 298), PlcParamType.Float),
|
||||||
|
new PlcParamMapping("txt_HardnessDamageThreshold", AddressOrDefault(plcConfig.HardnessPoSun, 400), PlcParamType.Float),
|
||||||
|
|
||||||
new PlcParamMapping("txt_BrittlenessTestTime", 410, PlcParamType.Int),
|
new PlcParamMapping("txt_BrittlenessTestTime", AddressOrDefault(plcConfig.FriabilityTestTime, 410), PlcParamType.Int),
|
||||||
new PlcParamMapping("txt_PreBrittlenessMass", 412, PlcParamType.Float),
|
new PlcParamMapping("txt_PreBrittlenessMass", ResolveWeightRegister(plcConfig.FriabilityWeightBefore, plcConfig.WeightBefore, 412), PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_PostBrittlenessMass", 414, PlcParamType.Float),
|
new PlcParamMapping("txt_PostBrittlenessMass", ResolveWeightRegister(plcConfig.FriabilityWeightAfter, plcConfig.WeightAfter, 414), PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_WeightLossRate", 416, PlcParamType.Int),
|
new PlcParamMapping("txt_WeightLossRate", 416, PlcParamType.Int),
|
||||||
|
|
||||||
new PlcParamMapping("txt_DisintegrationSpeed", 330, PlcParamType.Float),
|
new PlcParamMapping("txt_DisintegrationSpeed", AddressOrDefault(plcConfig.DisintegrationSpeed, 330), PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_DisintegrationTime", 420, PlcParamType.Int),
|
new PlcParamMapping("txt_DisintegrationTime", AddressOrDefault(plcConfig.DisintegrationTime, 420), PlcParamType.Int),
|
||||||
|
|
||||||
new PlcParamMapping("txt_DissolutionTime", 430, PlcParamType.Int),
|
new PlcParamMapping("txt_DissolutionTime", AddressOrDefault(plcConfig.Dissolution1Time, 430), PlcParamType.Int),
|
||||||
new PlcParamMapping("txt_Dissolution2Time", 440, PlcParamType.Int),
|
new PlcParamMapping("txt_Dissolution2Time", AddressOrDefault(plcConfig.Dissolution2Time, 440), PlcParamType.Int),
|
||||||
new PlcParamMapping("txt_Dissolution1SamplingInterval", 432, PlcParamType.Float),
|
new PlcParamMapping("txt_Dissolution1SamplingInterval", AddressOrDefault(plcConfig.Dissolution1SampleInterval, 432), PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_Dissolution2SamplingInterval", 442, PlcParamType.Float),
|
new PlcParamMapping("txt_Dissolution2SamplingInterval", AddressOrDefault(plcConfig.Dissolution2SampleInterval, 442), PlcParamType.Float),
|
||||||
|
|
||||||
|
new PlcParamMapping("txt_ForceCoefficient", 1320, PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_ForceCoefficient", 1320, PlcParamType.Float),
|
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
|
|
||||||
|
|
||||||
new PlcParamMapping("txt_TemperatureDisplay", 1430, PlcParamType.Float),
|
|
||||||
|
|
||||||
new PlcParamMapping("txt_MaxForceCollect", 72, PlcParamType.Float),//读取
|
new PlcParamMapping("txt_TemperatureDisplay", AddressOrDefault(plcConfig.DisintegrationTemp, 1430), PlcParamType.Float),
|
||||||
new PlcParamMapping("txt_ForceDisplay", 1314, PlcParamType.Float),//读取
|
|
||||||
new PlcParamMapping("txt_TemperatureCoefficient", 1428, PlcParamType.Float),//读取
|
new PlcParamMapping("txt_MaxForceCollect", AddressOrDefault(plcConfig.HardnessMax, 72), PlcParamType.Float),
|
||||||
};
|
new PlcParamMapping("txt_ForceDisplay", AddressOrDefault(plcConfig.HardnessShishilizhi, 1314), PlcParamType.Float),
|
||||||
|
new PlcParamMapping("txt_TemperatureCoefficient", 1428, PlcParamType.Float),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ushort AddressOrDefault(ushort configuredAddress, ushort fallbackAddress)
|
||||||
|
{
|
||||||
|
return configuredAddress != 0 ? configuredAddress : fallbackAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ushort ResolveWeightRegister(ushort primaryAddress, ushort compatibleAddress, ushort fallbackAddress)
|
||||||
|
{
|
||||||
|
if (primaryAddress != 0)
|
||||||
|
return primaryAddress;
|
||||||
|
|
||||||
|
return AddressOrDefault(compatibleAddress, fallbackAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class PlcParamMapping
|
internal class PlcParamMapping
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"IpAddress": "192.168.1.10",
|
"IpAddress": "192.168.1.10",
|
||||||
"Port": 502,
|
"Port": 502,
|
||||||
"SlaveId": 1,
|
"SlaveId": 1,
|
||||||
|
"FloatWordOrder": "LowWordFirst", // 三菱D寄存器REAL:低字在前,避免参数写入后PLC显示NaN
|
||||||
//"HardnessValue": 72,
|
//"HardnessValue": 72,
|
||||||
"HardnessStartCoil": 70, //硬度工位1启动测试M70
|
"HardnessStartCoil": 70, //硬度工位1启动测试M70
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user