diff --git a/CSI-Z173 吸入制剂药物测试仪(2).gxw b/CSI-Z173 吸入制剂药物测试仪(4).gxw similarity index 91% rename from CSI-Z173 吸入制剂药物测试仪(2).gxw rename to CSI-Z173 吸入制剂药物测试仪(4).gxw index 2c1f428..9d12467 100644 Binary files a/CSI-Z173 吸入制剂药物测试仪(2).gxw and b/CSI-Z173 吸入制剂药物测试仪(4).gxw differ diff --git a/Models/PlcConfiguration.cs b/Models/PlcConfiguration.cs index c881c0e..bcbb863 100644 --- a/Models/PlcConfiguration.cs +++ b/Models/PlcConfiguration.cs @@ -12,8 +12,8 @@ namespace AciTester.Models public class PlcConfiguration { // ========== 网络连接参数 ========== - public string IpAddress { get; set; } // PLC IP 地址 - public int Port { get; set; } // Modbus TCP 端口 + public string IpAddress { get; set; } = "192.168.1.10"; // PLC IP 地址 + public int Port { get; set; } = 502; // Modbus TCP 端口 public byte SlaveId { get; set; } = 1; // 从站地址(默认1) // 以下属性用于与上位机交互(但实际按工位读取,此处保留兼容) @@ -32,10 +32,10 @@ namespace AciTester.Models public ushort PressureRegisterStation2 { get; set; } // 工位2 public ushort PressureRegisterStation3 { get; set; } // 工位3 + public ushort ValveCoil { get; set; } = 5; // 假设 M5 对应线圈地址 5 - - public ushort PumpCoil { get; set; } // 高压超限 M180 + public ushort PumpCoil { get; set; } = 6; // 高压超限 M180 public ushort FlowRegister { get; set; } // 高压超限 M180 diff --git a/Services/ModbusTcpPlcService.cs b/Services/ModbusTcpPlcService.cs index 77eb6c2..d38421d 100644 --- a/Services/ModbusTcpPlcService.cs +++ b/Services/ModbusTcpPlcService.cs @@ -194,17 +194,25 @@ namespace AciTester.Services { await EnsureConnectedAsync(); var regs = await ReadHoldingRegistersAsync(startAddress, 2); - return (regs[0] << 16) | regs[1]; + + return regs[0]; // 暂时返回大端,您根据日志判断 } public async Task WriteInt32Async(ushort startAddress, int value) { await EnsureConnectedAsync(); - var 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 _master.WriteMultipleRegistersAsync(_config.SlaveId, startAddress, new ushort[] { high, low }); + ushort[] dwellTimeRegisters = ConvertIntToRegisters(value); + await _master.WriteMultipleRegistersAsync(1, startAddress, dwellTimeRegisters); + } + + // 将整数转换为寄存器数组(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; } } diff --git a/ViewModels/MainViewModel.cs b/ViewModels/MainViewModel.cs index 8ba630c..349aa53 100644 --- a/ViewModels/MainViewModel.cs +++ b/ViewModels/MainViewModel.cs @@ -18,7 +18,7 @@ namespace AciTester.ViewModels private CancellationTokenSource _testCts; private bool _alarmShownLow = false; private bool _alarmShownHigh = false; - + public IAsyncRelayCommand OpenValveCommand { get; } [ObservableProperty] private bool isConnected; @@ -34,6 +34,9 @@ namespace AciTester.ViewModels [ObservableProperty] private bool isTesting; + [ObservableProperty] + private bool canStopTest; // 控制“停止测试”按钮的启用状态 + [ObservableProperty] private int sampleTimeSeconds = 60; @@ -55,6 +58,17 @@ namespace AciTester.ViewModels [ObservableProperty] 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() { _config = new PlcConfiguration(); @@ -77,6 +91,7 @@ namespace AciTester.ViewModels ConnectCommand = new AsyncRelayCommand(ConnectAsync); DisconnectCommand = new RelayCommand(Disconnect); StartTestCommand = new AsyncRelayCommand(StartTestAsync); + StopTestCommand = new AsyncRelayCommand(StopTestAsync, () => IsTesting); CalculateCommand = new RelayCommand(CalculateResult); ExportReportCommand = new AsyncRelayCommand(ExportReportAsync); @@ -88,6 +103,28 @@ namespace AciTester.ViewModels RealTime = new RealTimeData(); 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) => @@ -101,8 +138,9 @@ namespace AciTester.ViewModels await WriteDefrostTimeSetAsync(RealTime.DefrostTimeSet); } }; - } + } + public IAsyncRelayCommand StopTestCommand { get; } public IAsyncRelayCommand ConnectCommand { get; } public IRelayCommand DisconnectCommand { get; } public IAsyncRelayCommand StartTestCommand { get; } @@ -113,6 +151,38 @@ namespace AciTester.ViewModels public IAsyncRelayCommand WriteDefrostTempSetCommand { get; } public IAsyncRelayCommand 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() { try @@ -179,10 +249,21 @@ namespace AciTester.ViewModels 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) { - Application.Current.Dispatcher.Invoke(() => - MessageBox.Show($"流量异常: {calibrated:F2} L/min", "警告", MessageBoxButton.OK, MessageBoxImage.Warning)); + //Application.Current.Dispatcher.Invoke(() => + // MessageBox.Show($"流量异常: {calibrated:F2} L/min", "警告", MessageBoxButton.OK, MessageBoxImage.Warning)); } } catch { } @@ -322,7 +403,7 @@ namespace AciTester.ViewModels IsTesting = true; _testCts = new CancellationTokenSource(); - + //StopTestCommand.NotifyCanExecuteChanged(); try { await _plcService.WriteCoilAsync(_config.PumpCoil, true); diff --git a/Views/MainWindow.xaml b/Views/MainWindow.xaml index 280c33a..b583d80 100644 --- a/Views/MainWindow.xaml +++ b/Views/MainWindow.xaml @@ -205,36 +205,56 @@ - + - - - -