This commit is contained in:
xyy
2026-04-09 21:43:30 +08:00
parent ae7b329792
commit e576af2b69
9 changed files with 251 additions and 23 deletions

View File

@@ -33,12 +33,45 @@ namespace MembranePoreTester.Communication
public ushort EnableCoil { get; set; } // 使能线圈M21只读状态
public ushort StopCoil { get; set; } // 停止线圈M7
public ushort UpAndDown1 { get; set; } // 高压/低压模式寄存器
public ushort UpAndDown2 { get; set; } // 高压/低压模式寄存器
public ushort UpAndDown3 { get; set; } // 高压/低压模式寄存器
public ushort StartCoil2 { get; set; } // 启动线圈M20
public ushort EnableCoil2 { get; set; } // 使能线圈M21只读状态
public ushort StopCoil2 { get; set; } // 停止线圈M7
public ushort StartCoil3 { get; set; } // 启动线圈M20
public ushort EnableCoil3 { get; set; } // 使能线圈M21只读状态
public ushort StopCoil3 { get; set; } // 停止线圈M7
// ========== 运维参数(用户可设置) ==========
public ushort PressureUpperLimit { get; set; } = 300; // 加压上限 D300
public ushort PressureUpperLimit2 { get; set; } = 302; // 加压上限 D300
public ushort PressureUpperLimit3 { get; set; } = 304; // 加压上限 D300
public ushort PressureRate { get; set; } = 280; // 加压速率 D280
public ushort PressureRate2 { get; set; } = 284; // 加压速率 D280
public ushort PressureRate3 { get; set; } = 286; // 加压速率 D280
public ushort HPCoeff11 { get; set; } = 74; // 1工位加压速率
public ushort HPCoeff12 { get; set; } = 92; // 1工位加压速率
public ushort HPCoeff13 { get; set; } = 96; // 1工位加压速率
// 高压/低压系数(每个工位独立)
public ushort HPCoeff1 { get; set; } = 3120; // 工位1 高压系数
@@ -92,6 +125,12 @@ namespace MembranePoreTester.Communication
public ushort LowPressAlarm { get; set; } // 低压超限 M195
public ushort Midnight1 { get; set; } // 高压超限 M180
public ushort Midnight2 { get; set; } // 低压超限 M195
public ushort Midnight3 { get; set; } // 高压超限 M180
}
/// <summary>

View File

@@ -51,6 +51,10 @@ namespace MembranePoreTester.Models
public string SpeedRate1 { get; set; }
public string SpeedRate2 { get; set; }
public string SpeedRate3 { get; set; }
public double MaxPoreSize => CalculateMaxPore();

View File

@@ -28,6 +28,20 @@ namespace MembranePoreTester.ViewModels
set => SetProperty(ref _record, value);
}
// 初始化,确保 StationId 在读取PLC前已设置
public void Initialize(int stationId)
{
StationId = stationId;
// 延迟读取当前PLC值以确保连接稳定
Task.Run(async () =>
{
await Task.Delay(200);
await ReadCurrentPlcAsync();
await ReadSpeedRateAsync();
});
}
public List<TestLiquid> Liquids => TestLiquid.Predefined;
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
@@ -140,20 +154,25 @@ namespace MembranePoreTester.ViewModels
try
{
float speedRate = 0;
ushort address = 0;
switch (StationId)
{
case 1:
speedRate = await _plcService. ReadFloatAsync(_plcConfig.HPCoeff11);
address = _plcConfig.HPCoeff11;
speedRate = await _plcService.ReadFloatAsync(address);
Record.SpeedRate1 = speedRate.ToString("F3");
break;
case 2:
address = _plcConfig.HPCoeff12;
speedRate = await _plcService.ReadFloatAsync(address);
Record.SpeedRate1 = speedRate.ToString("F3");
break;
case 3:
address = _plcConfig.HPCoeff13;
speedRate = await _plcService.ReadFloatAsync(address);
Record.SpeedRate1 = speedRate.ToString("F3");
break;
//case 2:
// speedRate = await _plcService.ReadFloatAsync(_plcConfig.PressureRate2);
// Record.SpeedRate2 = speedRate.ToString("F3");
// break;
//case 3:
// speedRate = await _plcService.ReadFloatAsync(_plcConfig.PressureRate3);
// Record.SpeedRate3 = speedRate.ToString("F3");
// break;
}
OnPropertyChanged(nameof(Record));
}

View File

@@ -83,6 +83,33 @@ namespace MembranePoreTester.ViewModels
}
private PressureModeItem _selectedInTakeMode;
private List<PressureModeItem> _inTakeModeList;
public List<PressureModeItem> InTakeModeList => _inTakeModeList ??= new List<PressureModeItem>
{
new PressureModeItem { Text = "底部进气", Value = 0 },
new PressureModeItem { Text = "顶部进气", Value = 1 }
};
public PressureModeItem SelecteInTakeMode
{
get => _selectedInTakeMode;
set
{
if (SetProperty(ref _selectedInTakeMode, value))
{
Task.Run(async () => await WriteInTakeModeAsync(value?.Text ?? "底部进气"));
}
}
}
private readonly IPlcService _plcService;
private readonly PlcConfiguration _plcConfig;
private bool _isPressing;
@@ -108,6 +135,19 @@ namespace MembranePoreTester.ViewModels
}
}
public string UpAndDown
{
get => _selectedInTakeMode?.Text ?? "底部";
set
{
var mode = InTakeModeList.FirstOrDefault(m => m.Text == value);
if (mode != null)
{
SelecteInTakeMode = mode;
}
}
}
public string PressButtonText
{
get => _pressButtonText;
@@ -174,7 +214,10 @@ namespace MembranePoreTester.ViewModels
// 仅在非抑制模式下将改变写回PLC避免把PLC读回的值再次写入造成循环
if (changed && !_suppressPressureValidation)
{
_ = _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureUpperLimit, (float)value);
ushort address = StationId == 1 ? _plcConfig.PressureUpperLimit
: StationId == 2 ? _plcConfig.PressureUpperLimit2
: _plcConfig.PressureUpperLimit3;
_ = _plcService.WriteMultipleRegistersAsync(address, (float)value);
}
}
}
@@ -187,7 +230,7 @@ namespace MembranePoreTester.ViewModels
if (SetProperty(ref _pressureRate, value))
{
// 值改变时写入PLC
_ = _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureRate, (float)value);
_ = _plcService.WriteMultipleRegistersAsync(StationId == 1 ? _plcConfig.PressureRate : StationId == 2 ? _plcConfig.PressureRate2 : _plcConfig.PressureRate3, (float)value);
}
}
}
@@ -197,8 +240,13 @@ namespace MembranePoreTester.ViewModels
{
try
{
float upperLimit = await _plcService.ReadFloatAsync(_plcConfig.PressureUpperLimit);
float rate = await _plcService.ReadFloatAsync(_plcConfig.PressureRate);
// 根据工位选择加压上限的PLC地址
ushort upperLimitAddress = StationId == 1 ? _plcConfig.PressureUpperLimit
: StationId == 2 ? _plcConfig.PressureUpperLimit2
: _plcConfig.PressureUpperLimit3;
float upperLimit = await _plcService.ReadFloatAsync(upperLimitAddress);
float rate = await _plcService.ReadFloatAsync(StationId == 1 ? _plcConfig.PressureRate : StationId == 2 ? _plcConfig.PressureRate2 : _plcConfig.PressureRate3);
@@ -241,7 +289,7 @@ namespace MembranePoreTester.ViewModels
StartCommand = new RelayCommand(async () =>
{
// 启动PLC
await WriteCoilAsync(_plcConfig.StartCoil, true);
await WriteCoilAsync(StationId == 1 ? _plcConfig.StartCoil : StationId == 2 ? _plcConfig.StartCoil2 : _plcConfig.StartCoil3, true);
// 启动孔分布自动采集
PoreDistributionVM.StartCollecting();
@@ -253,7 +301,7 @@ namespace MembranePoreTester.ViewModels
// 停止自动采集
PoreDistributionVM.StopCollecting();
// 停止PLC
await WriteCoilAsync(_plcConfig.StopCoil, true);
await WriteCoilAsync(StationId == 1 ? _plcConfig.StopCoil : StationId == 2 ? _plcConfig.StopCoil2 : _plcConfig.StopCoil3, true);
});
@@ -274,6 +322,7 @@ namespace MembranePoreTester.ViewModels
{
await ReadPressureModeAsync();
await ReadPressureParametersAsync(); // 新增:读取压力参数
await ReadInTakeModeAsync();
}, TaskScheduler.Default);
@@ -301,6 +350,44 @@ namespace MembranePoreTester.ViewModels
});
}
private async Task ReadInTakeModeAsync()
{
await SafeExecuteAsync($"ReadInTakeModeAsync{StationId}", async () =>
{
try
{
ushort address = 0;
if (StationId == 1)
{
address = _plcConfig.UpAndDown1;
}
else if (StationId == 2)
{
address = _plcConfig.UpAndDown2;
}
else if (StationId == 3)
{
address = _plcConfig.UpAndDown3;
}
ushort[] values = await _plcService.ReadHoldingRegistersAsync(address, 1);
ushort val = values[0];
string newValue = val == 0 ? "底部进气" : "顶部进气";
Application.Current.Dispatcher.Invoke(() =>
{
// 更新选中项
UpAndDown = newValue;
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"读取出口模式失败: {ex.Message}");
}
});
}
private async Task TogglePressAsync()
{
try
@@ -346,11 +433,11 @@ namespace MembranePoreTester.ViewModels
{
try
{
bool status = await _plcService.ReadCoilAsync(_plcConfig.EnableCoil); // 读取 M21
bool status = await _plcService.ReadCoilAsync(StationId == 1 ? _plcConfig.EnableCoil : StationId == 2 ? _plcConfig.EnableCoil2 : _plcConfig.EnableCoil3); // 读取 M21
EnableStatus = status;
bool pressStatus = await _plcService.ReadCoilAsync(_plcConfig.PressCoil);//这里也要更新加压的按钮状态
bool pressStatus = await _plcService.ReadCoilAsync(StationId == 1 ? _plcConfig.PressCoil : StationId == 2 ? _plcConfig.PressCoil2 : _plcConfig.PressCoil3);//这里也要更新加压的按钮状态
_isPressing = pressStatus;
@@ -401,6 +488,37 @@ namespace MembranePoreTester.ViewModels
}
private async Task WriteInTakeModeAsync(string mode)
{
if (IsDisposed) return;
ushort val = mode.ToString().Contains("底部") ? (ushort)0 : (ushort)1;
try
{
ushort address = 0;
if (StationId == 1)
{
address = _plcConfig.UpAndDown1;
}
else if (StationId == 2)
{
address = _plcConfig.UpAndDown2;
}
else if (StationId == 3)
{
address = _plcConfig.UpAndDown3;
}
await _plcService.WriteSingleRegisterAsync(address, val);
}
catch (Exception ex)
{
MessageBox.Show($"写出口模式失败: {ex.Message}");
}
}
private bool _isPoreDistributionActive;
public bool IsPoreDistributionActive
{
@@ -426,10 +544,13 @@ namespace MembranePoreTester.ViewModels
var station = new StationItem
{
Name = $"工位 {i}",
BubblePointVM = new BubblePointViewModel { StationId = i },
PoreDistributionVM = new PoreDistributionViewModel { StationId = i },
BubblePointVM = new BubblePointViewModel(),
PoreDistributionVM = new PoreDistributionViewModel(),
StationId = i
};
// 在构造完成后显式传入 StationId 以初始化 VM
station.BubblePointVM.Initialize(i);
station.PoreDistributionVM.Initialize(i);
Stations.Add(station);
}
@@ -456,6 +577,11 @@ namespace MembranePoreTester.ViewModels
bool highPressAlarm = await plc.ReadCoilAsync(config.HighPressAlarm);
bool lowPressAlarm = await plc.ReadCoilAsync(config.LowPressAlarm);
bool Midnight1 = await plc.ReadCoilAsync(config.Midnight1);
bool Midnight2 = await plc.ReadCoilAsync(config.Midnight2);
bool Midnight3 = await plc.ReadCoilAsync(config.Midnight3);
// 收集当前报警信息
var newAlarms = new List<string>();
if (smallFlowAlarm) newAlarms.Add("小流量计报警");
@@ -463,6 +589,10 @@ namespace MembranePoreTester.ViewModels
if (highPressAlarm) newAlarms.Add("高压超限");
if (lowPressAlarm) newAlarms.Add("低压超限");
if (Midnight1) newAlarms.Add("1工位漏夜");
if (Midnight2) newAlarms.Add("2工位漏夜");
if (Midnight3) newAlarms.Add("3工位漏夜");
// 更新UI避免频繁刷新集合导致界面闪烁直接替换内容
Application.Current.Dispatcher.Invoke(() =>
{

View File

@@ -731,6 +731,18 @@ namespace MembranePoreTester.ViewModels
set => SetProperty(ref _stationId, value);
}
// 初始化方法:在 MainViewModel 创建 StationItem 后调用,确保 StationId 已设置
public void Initialize(int stationId)
{
StationId = stationId;
// 延迟调用读取模式确保PLC连接稳定
Task.Run(async () =>
{
await Task.Delay(200);
await ReadPressureModeAsync();
});
}
public void SaveToDatabase()
{
var entity = new PoreDistributionEntity

View File

@@ -134,6 +134,8 @@
<Border DockPanel.Dock="Top" Background="White" CornerRadius="6" Padding="10" Margin="0,0,0,10" BorderBrush="#E9ECF0" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding PressureModeList}" SelectedItem="{Binding SelectedPressureMode}" Width="80"/>
<ComboBox ItemsSource="{Binding InTakeModeList}" SelectedItem="{Binding SelecteInTakeMode}" Width="80"/>
<Button Content="▶ 启动" Command="{Binding StartCommand}" Width="80" Background="#4CAF50"/>
<Button Content="⏹ 停止" Command="{Binding StopCommand}" Width="80" Background="#F44336"/>
<Button Content="{Binding PressButtonText}" Command="{Binding PressCommand}" Width="80" Background="#FF9800"/>

View File

@@ -22,6 +22,18 @@
"EnableCoil": 21, // 使能线圈M21状态反馈只读
"StopCoil": 7, // 停止线圈M7ON 停止测试
"StartCoil2": 30, // 启动线圈M20ON 启动测试程序
"EnableCoil2": 31, // 使能线圈M21状态反馈只读
"StopCoil2": 32, // 停止线圈M7ON 停止测试
"StartCoil3": 33, // 启动线圈M20ON 启动测试程序
"EnableCoil3": 34, // 使能线圈M21状态反馈只读
"StopCoil3": 35, // 停止线圈M7ON 停止测试
// 压力值系数(用于单位转换,例如 kPa 转 Pa 时设为 1000
"PressureFactor": 1000.0,
@@ -33,6 +45,8 @@
// ========== 运维参数设置(可读写) ==========
"PressureUpperLimit": 300, // 加压上限D300
"PressureUpperLimit2": 302, // 加压上限D300
"PressureUpperLimit3": 304, // 加压上限D300
"PressureRate": 280, // 加压速率D280
"PressureCoeff": 282, // 加压系数D282
@@ -74,14 +88,22 @@
"BigFlow2": 42, //
"BigFlow3": 46, //
"SmallFlowAlarm": 210,
"BigFlowAlarm": 213,
"HighPressAlarm": 180, //高压超限
"LowPressAlarm": 195 //低压超限
"LowPressAlarm": 195, //低压超限
"Midnight1": 50, // 漏夜1
"Midnight2": 51, // 漏夜2
"Midnight3": 52, // 漏夜3
"UpAndDown1": 18, // 漏夜3
"UpAndDown2": 20, // 漏夜3
"UpAndDown3": 22 // 漏夜3
}
}