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