This commit is contained in:
xyy
2026-03-27 21:35:32 +08:00
parent 6983e84c36
commit 2f1cacd097
10 changed files with 665 additions and 182 deletions

View File

@@ -126,9 +126,30 @@ namespace MembranePoreTester.ViewModels
_plcConfig = App.PlcConfig;
PressCommand = new RelayCommand(async () => await TogglePressAsync());
//BurstCommand = new RelayCommand(async () => await ReadBurstPressureAsync());
StartCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.StartCoil, true));
StopCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.StopCoil, true));
// 在 StationItem 构造函数中
StartCommand = new RelayCommand(async () =>
{
// 启动PLC
await WriteCoilAsync(_plcConfig.StartCoil, true);
// 启动孔分布自动采集
PoreDistributionVM.StartCollecting();
});
StopCommand = new RelayCommand(async () =>
{
// 停止自动采集
PoreDistributionVM.StopCollecting();
// 停止PLC
await WriteCoilAsync(_plcConfig.StopCoil, true);
});
// 启动定时器,每秒读取一次 M21 状态
_timer = new System.Windows.Threading.DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(1);
@@ -242,7 +263,12 @@ namespace MembranePoreTester.ViewModels
}
private bool _isPoreDistributionActive;
public bool IsPoreDistributionActive
{
get => _isPoreDistributionActive;
set => SetProperty(ref _isPoreDistributionActive, value);
}

View File

@@ -3,17 +3,171 @@ using MembranePoreTester.Helpers;
using MembranePoreTester.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Legends;
using OxyPlot.Series;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace MembranePoreTester.ViewModels
{
public class PoreDistributionViewModel : ViewModelBase, IStationViewModel
{
#region
public class PressureModeItem
{
public string Text { get; set; }
public int Value { get; set; }
public override string ToString()
{
return Text; // 直接返回要显示的文本
}
}
private PressureModeItem _selectedPressureMode;
private List<PressureModeItem> _pressureModeList;
public List<PressureModeItem> PressureModeList => _pressureModeList ??= new List<PressureModeItem>
{
new PressureModeItem { Text = "小流量", Value = 1 },
new PressureModeItem { Text = "大流量", Value = 0 }
};
public PressureModeItem SelectedPressureMode
{
get => _selectedPressureMode;
set
{
if (SetProperty(ref _selectedPressureMode, value))
{
Task.Run(async () => await WriteFlowModeAsync(value?.Text ?? "小流量"));
}
}
}
#endregion
// 添加字段
private System.Windows.Threading.DispatcherTimer _autoCollectTimer;
private bool _isCollecting = false;
// 添加公共方法供工位调用
public void StartCollecting()
{
if (!IsActive)
{
// 如果当前不在孔分布界面,不启动采集
return;
}
if (_isCollecting) return;
_isCollecting = true;
_autoCollectTimer = new System.Windows.Threading.DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
_autoCollectTimer.Tick += AutoCollectTimer_Tick;
_autoCollectTimer.Start();
}
public void StopCollecting()
{
_isCollecting = false;
_autoCollectTimer?.Stop();
_autoCollectTimer = null;
}
private async void AutoCollectTimer_Tick(object sender, EventArgs e)
{
if (!IsActive) return; // 不在当前标签页,跳过采集
try
{
// 1. 读取当前压力
float rawPressure = await _plcService.ReadPressureAsync(StationId);
double pressure = Math.Round(rawPressure,2);
double flow = 0;
if (TestMode == "湿膜")
{
float rawFlow = await _plcService.ReadWetFlowAsync();
flow = rawFlow;
}
else
{
float rawFlow = await _plcService.ReadDryFlowAsync();
flow = rawFlow;
}
flow = Math.Round(flow,2);
// 3. 在 DataPoints 中查找是否存在相同压力的行(允许微小误差)
var existing = Record.DataPoints.FirstOrDefault(p => Math.Abs(p.Pressure - pressure) < 0.001);
if (existing != null)
{
// 更新对应列
if (TestMode == "湿膜")
existing.WetFlow = flow;
else
existing.DryFlow = flow;
}
else
{
// 新增一行
var newPoint = new Models.DataPoint { Pressure = pressure };
if (TestMode == "湿膜")
newPoint.WetFlow = flow;
else
newPoint.DryFlow = flow;
Record.DataPoints.Add(newPoint);
}
// 4. 刷新曲线
UpdatePlot();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"自动采集失败: {ex.Message}");
}
}
/// <summary>
/// 清空所有数据点,重置表格和曲线
/// </summary>
public void ClearData()
{
// 清空数据点集合
Record.DataPoints.Clear();
// 重置曲线
UpdatePlot();
// 重置计算结果
AveragePoreSize = 0;
RangePercentage = 0;
// 可选:显示提示
System.Diagnostics.Debug.WriteLine("孔分布数据已清空");
}
private bool _isActive;
public bool IsActive
{
get => _isActive;
set => SetProperty(ref _isActive, value);
}
private PoreDistributionRecord _record = new();
private TestLiquid _selectedLiquid;
private bool _isCustomLiquid;
@@ -27,11 +181,11 @@ namespace MembranePoreTester.ViewModels
// 添加字段
private readonly IPlcService _plcService;
private readonly PlcConfiguration _plcConfig;
private DataPoint _selectedDataPoint;
private Models.DataPoint _selectedDataPoint;
// 添加属性
public DataPoint SelectedDataPoint
public Models.DataPoint SelectedDataPoint
{
get => _selectedDataPoint;
set => SetProperty(ref _selectedDataPoint, value);
@@ -127,8 +281,49 @@ namespace MembranePoreTester.ViewModels
Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot();
// 延迟2秒后读取确保连接稳定
Task.Delay(2000).ContinueWith(async _ =>
{
await ReadPressureModeAsync();
}, TaskScheduler.Default);
}
private async Task ReadPressureModeAsync()
{
try
{
ushort[] values = await _plcService.ReadHoldingRegistersAsync(_plcConfig.FlowModeRegister, 1);
ushort val = values[0];
string newValue = val == 0 ? "大流量" : "小流量";
Application.Current.Dispatcher.Invoke(() =>
{
// 更新选中项
HighLowPressure = newValue;
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"读取流量模式失败: {ex.Message}");
}
}
public string HighLowPressure
{
get => _selectedPressureMode?.Text ?? "小流量";
set
{
var mode = PressureModeList.FirstOrDefault(m => m.Text == value);
if (mode != null)
{
SelectedPressureMode = mode;
}
}
}
private async Task ReadPlcAsync()
{
@@ -156,7 +351,7 @@ namespace MembranePoreTester.ViewModels
else
{
// 新增一行
var newPoint = new DataPoint { Pressure = pressure };
var newPoint = new Models.DataPoint { Pressure = pressure };
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
@@ -178,7 +373,7 @@ namespace MembranePoreTester.ViewModels
private void AddDataPoint()
{
Record.DataPoints.Add(new DataPoint());
Record.DataPoints.Add(new Models.DataPoint());
}
private void RemoveDataPoint()
@@ -302,7 +497,7 @@ namespace MembranePoreTester.ViewModels
Record.DataPoints.Clear();
foreach (var dp in entity.DataPoints)
{
Record.DataPoints.Add(new DataPoint
Record.DataPoints.Add(new Models.DataPoint
{
Pressure = dp.Pressure,
WetFlow = dp.WetFlow,
@@ -347,19 +542,6 @@ namespace MembranePoreTester.ViewModels
set => SetProperty(ref _testMode, value);
}
private string _selectedFlowModeIndex; // 0=大流量1=小流量
public string SelectedFlowModeIndex
{
get => _selectedFlowModeIndex;
set
{
if (SetProperty(ref _selectedFlowModeIndex, value))
{
// 当选择变化时,写入 PLC 压力模式寄存器
Task.Run(async () => await WriteFlowModeAsync(value));
}
}
}
private OxyPlot.PlotModel _plotModel;
@@ -371,10 +553,10 @@ namespace MembranePoreTester.ViewModels
private async Task WriteFlowModeAsync(string mode)
{
float val = mode == "大流量" ? 0.0f : 1.0f;
ushort val = mode.ToString().Contains("大流量") ? (ushort)0 : (ushort)1;
try
{
await _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureModeRegister, val);
await _plcService.WriteSingleRegisterAsync(_plcConfig.FlowModeRegister, val);
}
catch (Exception ex)
{
@@ -382,6 +564,8 @@ namespace MembranePoreTester.ViewModels
}
}
private void UpdatePlot()
{
var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
@@ -391,12 +575,53 @@ namespace MembranePoreTester.ViewModels
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 model = new PlotModel
{
Title = "流量-压力曲线",
TitleFontSize = 14,
TitleFontWeight = 1
};
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 };
// 添加坐标轴
model.Axes.Add(new LinearAxis
{
Position = AxisPosition.Bottom,
Title = "压力 (kPa)",
TitleFontSize = 12
});
model.Axes.Add(new LinearAxis
{
Position = AxisPosition.Left,
Title = "流量 (L/min)",
TitleFontSize = 12
});
// 湿膜流量 - 使用更清晰的标题
var wetSeries = new LineSeries
{
Title = "● 湿膜流量 (Wet Flow)",
Color = OxyColors.Blue,
MarkerType = MarkerType.Circle,
MarkerSize = 4,
MarkerStroke = OxyColors.Blue,
MarkerFill = OxyColors.Blue,
StrokeThickness = 2
};
// 干膜流量 - 使用更清晰的标题
var drySeries = new LineSeries
{
Title = "▲ 干膜流量 (Dry Flow)",
Color = OxyColors.Red,
MarkerType = MarkerType.Triangle,
MarkerSize = 5,
MarkerStroke = OxyColors.Red,
MarkerFill = OxyColors.Red,
StrokeThickness = 2
};
foreach (var dp in sorted)
{
@@ -411,5 +636,10 @@ namespace MembranePoreTester.ViewModels
}
}
}