This commit is contained in:
Binary file not shown.
@@ -12,8 +12,8 @@ namespace AciTester.Models
|
|||||||
public class PlcConfiguration
|
public class PlcConfiguration
|
||||||
{
|
{
|
||||||
// ========== 网络连接参数 ==========
|
// ========== 网络连接参数 ==========
|
||||||
public string IpAddress { get; set; } // PLC IP 地址
|
public string IpAddress { get; set; } = "192.168.1.10"; // PLC IP 地址
|
||||||
public int Port { get; set; } // Modbus TCP 端口
|
public int Port { get; set; } = 502; // Modbus TCP 端口
|
||||||
public byte SlaveId { get; set; } = 1; // 从站地址(默认1)
|
public byte SlaveId { get; set; } = 1; // 从站地址(默认1)
|
||||||
|
|
||||||
// 以下属性用于与上位机交互(但实际按工位读取,此处保留兼容)
|
// 以下属性用于与上位机交互(但实际按工位读取,此处保留兼容)
|
||||||
@@ -32,10 +32,10 @@ namespace AciTester.Models
|
|||||||
public ushort PressureRegisterStation2 { get; set; } // 工位2
|
public ushort PressureRegisterStation2 { get; set; } // 工位2
|
||||||
public ushort PressureRegisterStation3 { get; set; } // 工位3
|
public ushort PressureRegisterStation3 { get; set; } // 工位3
|
||||||
|
|
||||||
|
public ushort ValveCoil { get; set; } = 5; // 假设 M5 对应线圈地址 5
|
||||||
|
|
||||||
|
|
||||||
|
public ushort PumpCoil { get; set; } = 6; // 高压超限 M180
|
||||||
public ushort PumpCoil { get; set; } // 高压超限 M180
|
|
||||||
|
|
||||||
|
|
||||||
public ushort FlowRegister { get; set; } // 高压超限 M180
|
public ushort FlowRegister { get; set; } // 高压超限 M180
|
||||||
|
|||||||
@@ -194,17 +194,25 @@ namespace AciTester.Services
|
|||||||
{
|
{
|
||||||
await EnsureConnectedAsync();
|
await EnsureConnectedAsync();
|
||||||
var regs = await ReadHoldingRegistersAsync(startAddress, 2);
|
var regs = await ReadHoldingRegistersAsync(startAddress, 2);
|
||||||
return (regs[0] << 16) | regs[1];
|
|
||||||
|
return regs[0]; // 暂时返回大端,您根据日志判断
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteInt32Async(ushort startAddress, int value)
|
public async Task WriteInt32Async(ushort startAddress, int value)
|
||||||
{
|
{
|
||||||
await EnsureConnectedAsync();
|
await EnsureConnectedAsync();
|
||||||
var bytes = BitConverter.GetBytes(value);
|
ushort[] dwellTimeRegisters = ConvertIntToRegisters(value);
|
||||||
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
|
await _master.WriteMultipleRegistersAsync(1, startAddress, dwellTimeRegisters);
|
||||||
ushort high = (ushort)((bytes[0] << 8) | bytes[1]);
|
}
|
||||||
ushort low = (ushort)((bytes[2] << 8) | bytes[3]);
|
|
||||||
await _master.WriteMultipleRegistersAsync(_config.SlaveId, startAddress, new ushort[] { high, low });
|
// 将整数转换为寄存器数组(2个寄存器)
|
||||||
|
private ushort[] ConvertIntToRegisters(int value)
|
||||||
|
{
|
||||||
|
byte[] bytes = BitConverter.GetBytes(value);
|
||||||
|
ushort[] registers = new ushort[2];
|
||||||
|
registers[0] = BitConverter.ToUInt16(bytes, 0); // 第一个寄存器(低位)
|
||||||
|
registers[1] = BitConverter.ToUInt16(bytes, 2); // 第二个寄存器(高位)
|
||||||
|
return registers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace AciTester.ViewModels
|
|||||||
private CancellationTokenSource _testCts;
|
private CancellationTokenSource _testCts;
|
||||||
private bool _alarmShownLow = false;
|
private bool _alarmShownLow = false;
|
||||||
private bool _alarmShownHigh = false;
|
private bool _alarmShownHigh = false;
|
||||||
|
public IAsyncRelayCommand OpenValveCommand { get; }
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool isConnected;
|
private bool isConnected;
|
||||||
|
|
||||||
@@ -34,6 +34,9 @@ namespace AciTester.ViewModels
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool isTesting;
|
private bool isTesting;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canStopTest; // 控制“停止测试”按钮的启用状态
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private int sampleTimeSeconds = 60;
|
private int sampleTimeSeconds = 60;
|
||||||
|
|
||||||
@@ -55,6 +58,17 @@ namespace AciTester.ViewModels
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool constantTempStartEnabled = true; // 是否允许恒温启动(除霜时为false)
|
private bool constantTempStartEnabled = true; // 是否允许恒温启动(除霜时为false)
|
||||||
|
|
||||||
|
public IAsyncRelayCommand StartPumpCommand { get; }
|
||||||
|
public IAsyncRelayCommand StopPumpCommand { get; }
|
||||||
|
// 阀门/泵状态(用于界面显示)
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool valveStatus; // true=开启, false=关闭
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool pumpStatus; // true=运行, false=停止
|
||||||
|
|
||||||
|
public IAsyncRelayCommand CloseValveCommand { get; }
|
||||||
|
|
||||||
public MainViewModel()
|
public MainViewModel()
|
||||||
{
|
{
|
||||||
_config = new PlcConfiguration();
|
_config = new PlcConfiguration();
|
||||||
@@ -77,6 +91,7 @@ namespace AciTester.ViewModels
|
|||||||
ConnectCommand = new AsyncRelayCommand(ConnectAsync);
|
ConnectCommand = new AsyncRelayCommand(ConnectAsync);
|
||||||
DisconnectCommand = new RelayCommand(Disconnect);
|
DisconnectCommand = new RelayCommand(Disconnect);
|
||||||
StartTestCommand = new AsyncRelayCommand(StartTestAsync);
|
StartTestCommand = new AsyncRelayCommand(StartTestAsync);
|
||||||
|
StopTestCommand = new AsyncRelayCommand(StopTestAsync, () => IsTesting);
|
||||||
CalculateCommand = new RelayCommand(CalculateResult);
|
CalculateCommand = new RelayCommand(CalculateResult);
|
||||||
ExportReportCommand = new AsyncRelayCommand(ExportReportAsync);
|
ExportReportCommand = new AsyncRelayCommand(ExportReportAsync);
|
||||||
|
|
||||||
@@ -88,6 +103,28 @@ namespace AciTester.ViewModels
|
|||||||
|
|
||||||
RealTime = new RealTimeData();
|
RealTime = new RealTimeData();
|
||||||
Calibration = new CalibrationConfig();
|
Calibration = new CalibrationConfig();
|
||||||
|
OpenValveCommand = new AsyncRelayCommand(async () =>
|
||||||
|
{
|
||||||
|
await _plcService.WriteCoilAsync(_config.ValveCoil, true);
|
||||||
|
ValveStatus = true;
|
||||||
|
});
|
||||||
|
CloseValveCommand = new AsyncRelayCommand(async () =>
|
||||||
|
{
|
||||||
|
await _plcService.WriteCoilAsync(_config.ValveCoil, false);
|
||||||
|
ValveStatus = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
StartPumpCommand = new AsyncRelayCommand(async () =>
|
||||||
|
{
|
||||||
|
await _plcService.WriteCoilAsync(_config.PumpCoil, true);
|
||||||
|
PumpStatus = true;
|
||||||
|
});
|
||||||
|
StopPumpCommand = new AsyncRelayCommand(async () =>
|
||||||
|
{
|
||||||
|
await _plcService.WriteCoilAsync(_config.PumpCoil, false);
|
||||||
|
PumpStatus = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// 监听属性变化,当除霜启动时更新恒温启动使能
|
// 监听属性变化,当除霜启动时更新恒温启动使能
|
||||||
RealTime.PropertyChanged += async (s, e) =>
|
RealTime.PropertyChanged += async (s, e) =>
|
||||||
@@ -101,8 +138,9 @@ namespace AciTester.ViewModels
|
|||||||
await WriteDefrostTimeSetAsync(RealTime.DefrostTimeSet);
|
await WriteDefrostTimeSetAsync(RealTime.DefrostTimeSet);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public IAsyncRelayCommand StopTestCommand { get; }
|
||||||
public IAsyncRelayCommand ConnectCommand { get; }
|
public IAsyncRelayCommand ConnectCommand { get; }
|
||||||
public IRelayCommand DisconnectCommand { get; }
|
public IRelayCommand DisconnectCommand { get; }
|
||||||
public IAsyncRelayCommand StartTestCommand { get; }
|
public IAsyncRelayCommand StartTestCommand { get; }
|
||||||
@@ -113,6 +151,38 @@ namespace AciTester.ViewModels
|
|||||||
public IAsyncRelayCommand<float> WriteDefrostTempSetCommand { get; }
|
public IAsyncRelayCommand<float> WriteDefrostTempSetCommand { get; }
|
||||||
public IAsyncRelayCommand<int> WriteDefrostTimeSetCommand { get; }
|
public IAsyncRelayCommand<int> WriteDefrostTimeSetCommand { get; }
|
||||||
|
|
||||||
|
private async Task StopTestAsync()
|
||||||
|
{
|
||||||
|
if (!IsTesting) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 停止真空泵
|
||||||
|
await _plcService.WriteCoilAsync(_config.PumpCoil, false);
|
||||||
|
IsPumpRunning = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"停止泵失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 重置状态
|
||||||
|
IsTesting = false;
|
||||||
|
CanStopTest = false;
|
||||||
|
_testCts?.Cancel(); // 取消倒计时
|
||||||
|
|
||||||
|
RemainingSeconds = 0;
|
||||||
|
|
||||||
|
// 更新按钮状态
|
||||||
|
StopTestCommand.NotifyCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//MessageBox.Show("测试已手动停止,请进行称重并录入数据。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async Task ConnectAsync()
|
private async Task ConnectAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -179,10 +249,21 @@ namespace AciTester.ViewModels
|
|||||||
RealTime.DifferentialPressure = calibratedImp - calibratedPump;
|
RealTime.DifferentialPressure = calibratedImp - calibratedPump;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 在 ReadRealTimeLoop 中添加
|
||||||
|
var valve = await _plcService.ReadCoilAsync(_config.ValveCoil);
|
||||||
|
var pump = await _plcService.ReadCoilAsync(_config.PumpCoil);
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
ValveStatus = valve;
|
||||||
|
PumpStatus = pump;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (calibrated < Calibration.FlowLowLimit || calibrated > Calibration.FlowHighLimit)
|
if (calibrated < Calibration.FlowLowLimit || calibrated > Calibration.FlowHighLimit)
|
||||||
{
|
{
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
//Application.Current.Dispatcher.Invoke(() =>
|
||||||
MessageBox.Show($"流量异常: {calibrated:F2} L/min", "警告", MessageBoxButton.OK, MessageBoxImage.Warning));
|
// MessageBox.Show($"流量异常: {calibrated:F2} L/min", "警告", MessageBoxButton.OK, MessageBoxImage.Warning));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
@@ -322,7 +403,7 @@ namespace AciTester.ViewModels
|
|||||||
|
|
||||||
IsTesting = true;
|
IsTesting = true;
|
||||||
_testCts = new CancellationTokenSource();
|
_testCts = new CancellationTokenSource();
|
||||||
|
//StopTestCommand.NotifyCanExecuteChanged();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _plcService.WriteCoilAsync(_config.PumpCoil, true);
|
await _plcService.WriteCoilAsync(_config.PumpCoil, true);
|
||||||
|
|||||||
@@ -205,36 +205,56 @@
|
|||||||
<!-- 主内容 (Row 3) -->
|
<!-- 主内容 (Row 3) -->
|
||||||
<Grid Grid.Row="3" Margin="0,10">
|
<Grid Grid.Row="3" Margin="0,10">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="280"/>
|
<ColumnDefinition Width="380"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- 左侧控制区 -->
|
<!-- 左侧控制区 -->
|
||||||
<Border Grid.Column="0" Background="White" CornerRadius="8" Padding="10" Margin="0,0,10,0" BorderBrush="#DDDDDD" BorderThickness="1">
|
<Border Grid.Column="0" Background="White" CornerRadius="8" Padding="10" Margin="0,0,10,0" BorderBrush="#DDDDDD" BorderThickness="1">
|
||||||
<StackPanel>
|
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="450">
|
||||||
<GroupBox Header="通讯控制" Margin="0,0,0,10">
|
<StackPanel>
|
||||||
<StackPanel>
|
<GroupBox Header="通讯控制" Margin="0,0,0,10">
|
||||||
<Button Command="{Binding ConnectCommand}" Content="连接PLC" Height="45"/>
|
<StackPanel>
|
||||||
<Button Command="{Binding DisconnectCommand}" Content="断开连接" Height="45"/>
|
<Button Command="{Binding ConnectCommand}" Content="连接PLC" Height="45"/>
|
||||||
</StackPanel>
|
<Button Command="{Binding DisconnectCommand}" Content="断开连接" Height="45"/>
|
||||||
</GroupBox>
|
|
||||||
<GroupBox Header="采样参数" Margin="0,0,0,10">
|
|
||||||
<StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal" Margin="0,5">
|
|
||||||
<TextBlock Text="采样时间(秒):" Width="100" VerticalAlignment="Center" FontSize="14"/>
|
|
||||||
<TextBox Text="{Binding SampleTimeSeconds}" Width="80" IsEnabled="{Binding IsTesting, Converter={StaticResource InverseBoolConverter}}"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Command="{Binding StartTestCommand}" Content="开始测试" Height="45" Margin="0,10,0,0" IsEnabled="{Binding IsTesting, Converter={StaticResource InverseBoolConverter}}"/>
|
</GroupBox>
|
||||||
<TextBlock Text="测试进行中..." Visibility="{Binding IsTesting, Converter={StaticResource BoolToVisibilityConverter}}" Foreground="Orange" FontWeight="Bold" FontSize="14" Margin="0,5,0,0" HorizontalAlignment="Center"/>
|
<GroupBox Header="采样参数" Margin="0,0,0,10">
|
||||||
</StackPanel>
|
<StackPanel>
|
||||||
</GroupBox>
|
<!-- 采样时间设置 -->
|
||||||
<GroupBox Header="数据分析">
|
<StackPanel Orientation="Horizontal" Margin="0,5">
|
||||||
<StackPanel>
|
<TextBlock Text="采样时间(秒):" Width="100" VerticalAlignment="Center" FontSize="14"/>
|
||||||
<Button Command="{Binding CalculateCommand}" Content="计算结果" Height="45"/>
|
<TextBox Text="{Binding SampleTimeSeconds}" Width="80" IsEnabled="{Binding IsTesting, Converter={StaticResource InverseBoolConverter}}"/>
|
||||||
<Button Command="{Binding ExportReportCommand}" Content="导出报告" Height="45"/>
|
</StackPanel>
|
||||||
</StackPanel>
|
|
||||||
</GroupBox>
|
<!-- 阀门与泵独立控制(手动调试用) -->
|
||||||
</StackPanel>
|
<Border BorderBrush="#CCCCCC" BorderThickness="1" CornerRadius="5" Padding="5" Margin="0,5">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="手动控制" FontWeight="Bold" FontSize="12" Foreground="Gray" Margin="0,0,0,5"/>
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<Button Command="{Binding OpenValveCommand}" Content="开阀(M5)" Width="70" Height="30" Margin="2" Background="#3498DB" Foreground="White"/>
|
||||||
|
<Button Command="{Binding CloseValveCommand}" Content="关阀(M5)" Width="70" Height="30" Margin="2" Background="#E74C3C" Foreground="White"/>
|
||||||
|
<Button Command="{Binding StartPumpCommand}" Content="启泵(M6)" Width="70" Height="30" Margin="2" Background="#2ECC71" Foreground="White"/>
|
||||||
|
<Button Command="{Binding StopPumpCommand}" Content="停泵(M6)" Width="70" Height="30" Margin="2" Background="#E67E22" Foreground="White"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 自动测试按钮 -->
|
||||||
|
<Button Command="{Binding StartTestCommand}" Content="开始测试" Height="45" Margin="0,10,0,0" IsEnabled="{Binding IsTesting, Converter={StaticResource InverseBoolConverter}}"/>
|
||||||
|
<TextBlock Text="测试进行中..." Visibility="{Binding IsTesting, Converter={StaticResource BoolToVisibilityConverter}}" Foreground="Orange" FontWeight="Bold" FontSize="14" Margin="0,5,0,0" HorizontalAlignment="Center"/>
|
||||||
|
<Button Command="{Binding StopTestCommand}" Content="停止测试" Height="45" Margin="0,10,0,0" Background="#E74C3C" Foreground="White" />
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
<GroupBox Header="数据分析">
|
||||||
|
<StackPanel>
|
||||||
|
<Button Command="{Binding CalculateCommand}" Content="计算结果" Height="45"/>
|
||||||
|
<Button Command="{Binding ExportReportCommand}" Content="导出报告" Height="45"/>
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- 右侧称重数据表格 -->
|
<!-- 右侧称重数据表格 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user