更新20260518

This commit is contained in:
GukSang.Jin
2026-05-19 18:22:00 +08:00
parent 00c224ceff
commit 2f4388723c
5 changed files with 83 additions and 43 deletions

View File

@@ -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,7 +15,8 @@
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
}
}

View File

@@ -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();
}
}

View File

@@ -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();
});

View File

@@ -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", 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_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_DisintegrationSpeed", 330, PlcParamType.Float),
new PlcParamMapping("txt_DisintegrationTime", 420, 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_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_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_ForceCoefficient", 1320, PlcParamType.Float),
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
new PlcParamMapping("txt_TemperatureDisplay", 1430, PlcParamType.Float),
new PlcParamMapping("txt_ForceCoefficient", 1320, PlcParamType.Float),
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
new PlcParamMapping("txt_MaxForceCollect", 72, PlcParamType.Float),//读取
new PlcParamMapping("txt_ForceDisplay", 1314, PlcParamType.Float),//读取
new PlcParamMapping("txt_TemperatureCoefficient", 1428, PlcParamType.Float),//读取
};
new PlcParamMapping("txt_TemperatureDisplay", AddressOrDefault(plcConfig.DisintegrationTemp, 1430), 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

View File

@@ -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