From 7bbf8292245493fd43bda22ac3095e520f255171 Mon Sep 17 00:00:00 2001 From: xyy <544939200@qq.com> Date: Tue, 24 Mar 2026 19:33:35 +0800 Subject: [PATCH] --- Helpers/PlcConfiguration.cs | 34 +++++ Models/DataPoint.cs | 1 + Service/ModbusTcpPlcService.cs | 14 ++ ViewModels/BubblePointViewModel.cs | 19 ++- ViewModels/MainViewModel.cs | 13 ++ ViewModels/PoreDistributionViewModel.cs | 80 +++++++++- ViewModels/ViewModelBase.cs | 13 +- Views/BubblePointView.xaml | 1 + Views/MainWindow.xaml | 2 +- Views/MainWindow.xaml.cs | 12 ++ Views/ParameterWindow.xaml | 120 +++++++++++++++ Views/ParameterWindow.xaml.cs | 186 ++++++++++++++++++++++++ Views/PoreDistributionView.xaml | 14 +- appsettings.json | 40 ++++- 泡压法膜孔径分析仪.csproj | 2 + 15 files changed, 542 insertions(+), 9 deletions(-) create mode 100644 Views/ParameterWindow.xaml create mode 100644 Views/ParameterWindow.xaml.cs diff --git a/Helpers/PlcConfiguration.cs b/Helpers/PlcConfiguration.cs index 88efea9..4d26440 100644 --- a/Helpers/PlcConfiguration.cs +++ b/Helpers/PlcConfiguration.cs @@ -25,6 +25,36 @@ + + + public ushort PressureUpperLimit { get; set; } = 300; + public ushort PressureRate { get; set; } = 280; + public ushort PressureCoeff { get; set; } = 282; + public ushort HPCoeff1 { get; set; } = 3120; + public ushort LPCoeff1 { get; set; } = 3122; + public ushort HPCoeff2 { get; set; } = 3124; + public ushort LPCoeff2 { get; set; } = 3126; + public ushort HPCoeff3 { get; set; } = 3128; + public ushort LPCoeff3 { get; set; } = 3130; + public ushort LargeFlowCoeff1 { get; set; } = 3048; + public ushort SmallFlowCoeff1 { get; set; } = 380; + public ushort LargeFlowCoeff2 { get; set; } = 1218; + public ushort SmallFlowCoeff2 { get; set; } = 1318; + public ushort LargeFlowCoeff3 { get; set; } = 1418; + public ushort SmallFlowCoeff3 { get; set; } = 1468; + public ushort FlowModeRegister1 { get; set; } = 5; // 工位1流量模式 (0=大,1=小) + public ushort FlowModeRegister2 { get; set; } = 6; + public ushort FlowModeRegister3 { get; set; } = 7; + // 校准系数地址(需与PLC约定) + public ushort PressureCalibZero { get; set; } = 3200; + public ushort PressureCalibSpan { get; set; } = 3202; + public ushort FlowCalibZero { get; set; } = 3204; + public ushort FlowCalibSpan { get; set; } = 3206; + + + + + } @@ -40,6 +70,10 @@ Task WriteRegisterAsync(ushort registerAddress, ushort value); // 写寄存器 Task ReadCoilAsync(ushort coilAddress); // 新增:读取线圈状态 + + + Task ReadHoldingRegistersAsync(ushort startAddress, ushort count); + Task WriteSingleRegisterAsync(ushort registerAddress, ushort value); } } \ No newline at end of file diff --git a/Models/DataPoint.cs b/Models/DataPoint.cs index 4bb355c..34501e9 100644 --- a/Models/DataPoint.cs +++ b/Models/DataPoint.cs @@ -5,5 +5,6 @@ public double Pressure { get; set; } // 压力 public double WetFlow { get; set; } // 湿膜流量(L/min) public double DryFlow { get; set; } // 干膜流量(L/min) + } } \ No newline at end of file diff --git a/Service/ModbusTcpPlcService.cs b/Service/ModbusTcpPlcService.cs index 3ff194d..d304d17 100644 --- a/Service/ModbusTcpPlcService.cs +++ b/Service/ModbusTcpPlcService.cs @@ -77,6 +77,20 @@ namespace MembranePoreTester.Communication return result[0]; } + + public async Task ReadHoldingRegistersAsync(ushort startAddress, ushort count) + { + await EnsureConnectedAsync(); + return await _master.ReadHoldingRegistersAsync(_config.SlaveId, startAddress, count); + } + + public async Task WriteSingleRegisterAsync(ushort registerAddress, ushort value) + { + await EnsureConnectedAsync(); + await _master.WriteSingleRegisterAsync(_config.SlaveId, registerAddress, value); + } + + // 新增读取压力(根据工位) public async Task ReadPressureAsync(int stationId) { diff --git a/ViewModels/BubblePointViewModel.cs b/ViewModels/BubblePointViewModel.cs index 2dcb4aa..2086fd4 100644 --- a/ViewModels/BubblePointViewModel.cs +++ b/ViewModels/BubblePointViewModel.cs @@ -85,6 +85,8 @@ namespace MembranePoreTester.ViewModels public ICommand CalculateCommand { get; } public ICommand GenerateReportCommand { get; } + public ICommand OpenPressureCalibCommand { get; } + public BubblePointViewModel() { @@ -96,6 +98,7 @@ namespace MembranePoreTester.ViewModels ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync()); SaveCommand = new RelayCommand(SaveToDatabase); ExportCommand = new RelayCommand(ExportToExcel); + OpenPressureCalibCommand = new RelayCommand(OpenPressureCalibration); } @@ -194,7 +197,21 @@ namespace MembranePoreTester.ViewModels public ICommand ExportCommand { get; } - + private void OpenPressureCalibration() + { + // 使用简单的输入框获取新零点系数和量程系数 + string zeroStr = Microsoft.VisualBasic.Interaction.InputBox("请输入压力零点系数", "压力校准", "0"); + string spanStr = Microsoft.VisualBasic.Interaction.InputBox("请输入压力量程系数", "压力校准", "1"); + if (float.TryParse(zeroStr, out float zero) && float.TryParse(spanStr, out float span)) + { + Task.Run(async () => + { + await WriteFloatAsync(_plcConfig.PressureCalibZero, zero); + await WriteFloatAsync(_plcConfig.PressureCalibSpan, span); + MessageBox.Show("压力校准系数已写入", "完成"); + }); + } + } private void ExportToExcel() { diff --git a/ViewModels/MainViewModel.cs b/ViewModels/MainViewModel.cs index 6f0f362..35c7c93 100644 --- a/ViewModels/MainViewModel.cs +++ b/ViewModels/MainViewModel.cs @@ -127,8 +127,21 @@ namespace MembranePoreTester.ViewModels MessageBox.Show($"写压力模式失败: {ex.Message}"); } } + + + + + + + } + + + + + + public MainViewModel() { for (int i = 1; i <= 3; i++) diff --git a/ViewModels/PoreDistributionViewModel.cs b/ViewModels/PoreDistributionViewModel.cs index f4848d7..1a5a625 100644 --- a/ViewModels/PoreDistributionViewModel.cs +++ b/ViewModels/PoreDistributionViewModel.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Windows; using System.Windows.Input; + namespace MembranePoreTester.ViewModels { public class PoreDistributionViewModel : ViewModelBase, IStationViewModel @@ -122,6 +123,10 @@ namespace MembranePoreTester.ViewModels ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync()); SaveCommand = new RelayCommand(SaveToDatabase); ExportCommand = new RelayCommand(ExportToExcel); + OpenFlowCalibCommand = new RelayCommand(OpenFlowCalibration); + + + Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot(); } @@ -220,8 +225,20 @@ namespace MembranePoreTester.ViewModels ReportGenerator.GeneratePoreDistributionReport(Record); } - - + private void OpenFlowCalibration() + { + string zeroStr = Microsoft.VisualBasic.Interaction.InputBox("请输入流量零点系数", "流量校准", "0"); + string spanStr = Microsoft.VisualBasic.Interaction.InputBox("请输入流量量程系数", "流量校准", "1"); + if (float.TryParse(zeroStr, out float zero) && float.TryParse(spanStr, out float span)) + { + Task.Run(async () => + { + await WriteFloatAsync(_plcConfig.FlowCalibZero, zero); + await WriteFloatAsync(_plcConfig.FlowCalibSpan, span); + MessageBox.Show("流量校准系数已写入", "完成"); + }); + } + } private int _stationId; public int StationId @@ -301,7 +318,7 @@ namespace MembranePoreTester.ViewModels public ICommand SaveCommand { get; } - + public ICommand OpenFlowCalibCommand { get; } public ICommand ExportCommand { get; } @@ -330,6 +347,63 @@ namespace MembranePoreTester.ViewModels set => SetProperty(ref _testMode, value); } + private int _selectedFlowModeIndex; // 0=大流量,1=小流量 + public int SelectedFlowModeIndex + { + get => _selectedFlowModeIndex; + set + { + if (SetProperty(ref _selectedFlowModeIndex, value)) + { + ushort reg = StationId switch + { + 1 => _plcConfig.FlowModeRegister1, + 2 => _plcConfig.FlowModeRegister2, + 3 => _plcConfig.FlowModeRegister3, + _ => 0 + }; + Task.Run(async () => await _plcService.WriteSingleRegisterAsync(reg, (ushort)value)); + } + } + } + + + private OxyPlot.PlotModel _plotModel; + public OxyPlot.PlotModel PlotModel + { + get => _plotModel; + set => SetProperty(ref _plotModel, value); + } + + + private void UpdatePlot() + { + var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList(); + if (sorted.Count == 0) + { + PlotModel = null; + return; + } + + var model = new OxyPlot.PlotModel { Title = "流量-压力曲线" }; + model.Axes.Add(new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Bottom, Title = "压力" }); + model.Axes.Add(new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Left, Title = "流量 (L/min)" }); + + var wetSeries = new OxyPlot.Series.LineSeries { Title = "湿膜流量", Color = OxyPlot.OxyColors.Blue, MarkerType = OxyPlot.MarkerType.Circle }; + var drySeries = new OxyPlot.Series.LineSeries { Title = "干膜流量", Color = OxyPlot.OxyColors.Red, MarkerType = OxyPlot.MarkerType.Circle }; + + foreach (var dp in sorted) + { + wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow)); + drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow)); + } + + model.Series.Add(wetSeries); + model.Series.Add(drySeries); + + PlotModel = model; + } + } } \ No newline at end of file diff --git a/ViewModels/ViewModelBase.cs b/ViewModels/ViewModelBase.cs index 0785cd1..86f3e4f 100644 --- a/ViewModels/ViewModelBase.cs +++ b/ViewModels/ViewModelBase.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using MembranePoreTester.Communication; +using System.ComponentModel; using System.Runtime.CompilerServices; namespace MembranePoreTester.ViewModels @@ -19,5 +20,15 @@ namespace MembranePoreTester.ViewModels OnPropertyChanged(propertyName); return true; } + + protected async Task WriteFloatAsync(ushort address, float value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian) Array.Reverse(bytes); + ushort high = (ushort)((bytes[0] << 8) | bytes[1]); + ushort low = (ushort)((bytes[2] << 8) | bytes[3]); + await App.PlcService.WriteSingleRegisterAsync(address, high); + await App.PlcService.WriteSingleRegisterAsync((ushort)(address + 1), low); + } } } \ No newline at end of file diff --git a/Views/BubblePointView.xaml b/Views/BubblePointView.xaml index 3153ac2..2d75cc8 100644 --- a/Views/BubblePointView.xaml +++ b/Views/BubblePointView.xaml @@ -78,6 +78,7 @@ +