diff --git a/CSI-H238M/CSI-H238M/Services/ModbusService.cs b/CSI-H238M/CSI-H238M/Services/ModbusService.cs index 3484130..5da1cd2 100644 --- a/CSI-H238M/CSI-H238M/Services/ModbusService.cs +++ b/CSI-H238M/CSI-H238M/Services/ModbusService.cs @@ -626,6 +626,41 @@ namespace COFTester.Services } } + /// + /// 触发测试停止按钮 M32(复归型) + /// M32 需要写入脉冲信号:true -> 延迟 -> false + /// + public virtual async Task TriggerTestStopAsync() + { + try + { + if (_modbusMaster != null && _isConnected) + { + const ushort STOP_BUTTON_ADDRESS = 32; // M32 停止按钮 + + System.Diagnostics.Debug.WriteLine($"[Modbus] 触发测试停止按钮 M{STOP_BUTTON_ADDRESS}"); + + await _modbusMaster.WriteSingleCoilAsync(1, STOP_BUTTON_ADDRESS, true); + System.Diagnostics.Debug.WriteLine($"[Modbus] M{STOP_BUTTON_ADDRESS} = true"); + + await Task.Delay(100); + + await _modbusMaster.WriteSingleCoilAsync(1, STOP_BUTTON_ADDRESS, false); + System.Diagnostics.Debug.WriteLine($"[Modbus] M{STOP_BUTTON_ADDRESS} = false"); + + await Task.Delay(100); + + System.Diagnostics.Debug.WriteLine($"[Modbus] M{STOP_BUTTON_ADDRESS} 脉冲信号发送完成"); + } + } + catch (Exception ex) + { + OnErrorOccurred($"触发测试停止失败: {ex.Message}"); + System.Diagnostics.Debug.WriteLine($"[Modbus] 触发 M32 异常: {ex.Message}"); + throw; + } + } + /// /// 读取测试状态标记位 M31 /// M31: 1=测试中,0=停止 @@ -655,6 +690,46 @@ namespace COFTester.Services } } + /// + /// 读取当前实时传感器数据,用于非测试状态下的界面实时显示。 + /// + public virtual async Task ReadCurrentDataAsync() + { + try + { + if (_modbusMaster == null || !_isConnected) + { + return null; + } + + var dataPoint = await ReadSensorDataAsync(); + if (dataPoint == null) + { + return null; + } + + try + { + var (verticalPos, horizontalPos) = await ReadPositionDataAsync(); + dataPoint.VerticalPosition = verticalPos; + dataPoint.HorizontalPosition = horizontalPos; + } + catch (Exception ex) + { + dataPoint.VerticalPosition = 0; + dataPoint.HorizontalPosition = 0; + System.Diagnostics.Debug.WriteLine($"[Modbus] 读取实时位置数据失败: {ex.Message}"); + } + + return dataPoint; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[Modbus] 读取实时数据异常: {ex.Message}"); + return null; + } + } + /// /// 写入启动/停止寄存器 M31(已弃用,请使用 TriggerTestStartAsync) /// M30 复归型, M31 标注为 1=开始,0=停止 diff --git a/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs b/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs index 1235868..23af5bb 100644 --- a/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs +++ b/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs @@ -21,6 +21,7 @@ namespace COFTester.ViewModels private readonly IDataAcquisitionService _daqService; private readonly DataProcessingService _processingService; private readonly DispatcherTimer _clockTimer; + private readonly DispatcherTimer _liveSensorTimer; private readonly DispatcherTimer _m31StatusTimer; // M31状态检查定时器 private WpfPlot? _wpfPlot; private readonly AppConfig _config; @@ -40,6 +41,9 @@ namespace COFTester.ViewModels private bool _showAllCurves = true; private int _testCounter = 0; private bool _disposed = false; + private bool _isRefreshingLiveSensorData = false; + private bool _isTestTransitioning = false; + private bool _stopRequestedByUser = false; private string _selectedDirection = ""; // 选中的方向:Up/Down/Right/Left private string _resetButtonText; // 复位按钮文本 private string _testButtonText; // 测试按钮文本 @@ -69,7 +73,7 @@ namespace COFTester.ViewModels DisconnectCommand = new RelayCommand(Disconnect, () => IsConnected && !_isTesting); ToggleConnectionCommand = new AsyncRelayCommand(ToggleConnectionAsync, () => !_isConnecting && !_isTesting); StartCommand = new RelayCommand(StartTest, CanStartTest); - StopCommand = new RelayCommand(StopTest, () => _isTesting); + StopCommand = new RelayCommand(StopTest, CanStopTest); ResetCommand = new RelayCommand(Reset, () => !_isTesting && IsConnected); SwitchLanguageCommand = new RelayCommand(SwitchLanguage); OpenConfigCommand = new RelayCommand(OpenConfig); @@ -111,6 +115,13 @@ namespace COFTester.ViewModels _m31StatusTimer.Tick += async (s, e) => await CheckM31StatusAsync(); _m31StatusTimer.Start(); + _liveSensorTimer = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(200) + }; + _liveSensorTimer.Tick += async (s, e) => await RefreshLiveSensorDataAsync(); + _liveSensorTimer.Start(); + // 根據配置自動連接 AutoConnectOnStartup(); } @@ -173,8 +184,9 @@ namespace COFTester.ViewModels if (oldCanStartTest != _canStartTest) { System.Diagnostics.Debug.WriteLine($"[ViewModel] 开始按钮可用性变化: {_canStartTest}"); - CommandManager.InvalidateRequerySuggested(); } + + CommandManager.InvalidateRequerySuggested(); } /// @@ -184,6 +196,48 @@ namespace COFTester.ViewModels { return _canStartTest; } + + private bool CanStopTest() + { + return IsConnected && (_isTesting || _m31Status || _isTestTransitioning); + } + + private async Task RefreshLiveSensorDataAsync() + { + if (_disposed || _isRefreshingLiveSensorData || !IsConnected || _isTesting || _isTestTransitioning) + { + return; + } + + if (_daqService is not ModbusServiceBase modbusService) + { + return; + } + + try + { + _isRefreshingLiveSensorData = true; + + var point = await modbusService.ReadCurrentDataAsync(); + if (point == null) + { + return; + } + + CurrentForce = point.Force; + CurrentDisp = point.Displacement; + LiftPosition = point.VerticalPosition; + HorizontalPosition = point.HorizontalPosition; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[ViewModel] 实时数值刷新失败: {ex.Message}"); + } + finally + { + _isRefreshingLiveSensorData = false; + } + } /// /// 設置圖表控件(由TestPage調用) @@ -575,6 +629,13 @@ namespace COFTester.ViewModels TestButtonText = Lang.StartTest; // 测试完成后恢复按钮文本 _m31Status = false; // 测试完成,M31应该为0 UpdateCanStartTest(); // 更新按钮可用性 + if (_stopRequestedByUser) + { + _stopRequestedByUser = false; + StatusMessage = Lang.TestStopped; + return; + } + StatusMessage = Lang.TestCompleted; // 数据处理与计算 @@ -661,6 +722,7 @@ namespace COFTester.ViewModels _m31Status = await modbusService.ReadTestStatusAsync(); System.Diagnostics.Debug.WriteLine($"[ViewModel] 连接后M31状态: {(_m31Status ? "1 (测试中)" : "0 (停止)")}"); UpdateCanStartTest(); + await RefreshLiveSensorDataAsync(); } catch (Exception ex) { @@ -799,6 +861,10 @@ namespace COFTester.ViewModels // return; //} + _stopRequestedByUser = false; + _isTestTransitioning = true; + CommandManager.InvalidateRequerySuggested(); + _realTimePoints.Clear(); OnPropertyChanged(nameof(DataPointsCount)); LatestResult = null; @@ -842,6 +908,8 @@ namespace COFTester.ViewModels { // 测试未启动,保持原状态 _m31Status = false; // 更新M31状态 + _isTestTransitioning = false; + CommandManager.InvalidateRequerySuggested(); StatusMessage = "测试启动失败,请检查设备"; System.Diagnostics.Debug.WriteLine("[ViewModel] M31 = 0,测试未启动"); } @@ -853,6 +921,8 @@ namespace COFTester.ViewModels { StatusMessage = $"启动测试失败: {ex.Message}"; _m31Status = false; + _isTestTransitioning = false; + CommandManager.InvalidateRequerySuggested(); System.Diagnostics.Debug.WriteLine($"[ViewModel] 启动测试异常: {ex.Message}"); }); } @@ -861,21 +931,43 @@ namespace COFTester.ViewModels // _daqService.StartDirectionTest(_selectedDirection); // 暂时注释掉 _daqService.StartAcquisition(Parameters); + _isTestTransitioning = false; + CommandManager.InvalidateRequerySuggested(); } - private void StopTest() + private async void StopTest() { + _stopRequestedByUser = true; + _isTestTransitioning = true; + CommandManager.InvalidateRequerySuggested(); + // M30 复归型按钮,M31 状态标记位(1=测试中,0=停止) // M31 是只读状态位,由 PLC 控制,我们只需停止数据采集 // PLC 会自动将 M31 设置为 0 - _daqService.StopAcquisition(); - IsTesting = false; - TestButtonText = Lang.StartTest; // 恢复按钮文本为"开始测试" - StatusMessage = Lang.TestStopped; - UpdateCanStartTest(); // 更新按钮可用性 + try + { + if (_daqService is ModbusServiceBase modbusService) + { + await modbusService.TriggerTestStopAsync(); + } + } + catch (Exception ex) + { + StatusMessage = $"停止测试失败: {ex.Message}"; + System.Diagnostics.Debug.WriteLine($"[ViewModel] 停止测试异常: {ex.Message}"); + } + finally + { + _daqService.StopAcquisition(); + IsTesting = false; + TestButtonText = Lang.StartTest; + StatusMessage = Lang.TestStopped; + _isTestTransitioning = false; + UpdateCanStartTest(); - System.Diagnostics.Debug.WriteLine("[ViewModel] 停止测试,等待 PLC 将 M31 设置为 0"); + System.Diagnostics.Debug.WriteLine("[ViewModel] 已发送 M32 停止命令,并停止本地数据采集"); + } } private async void Reset() @@ -1626,6 +1718,7 @@ namespace COFTester.ViewModels // 停止M31状态检查定时器 _m31StatusTimer?.Stop(); + _liveSensorTimer?.Stop(); // 取消訂閱事件 if (_daqService != null) diff --git a/CSI-H238M/CSI-H238M/Views/MainWindow.xaml b/CSI-H238M/CSI-H238M/Views/MainWindow.xaml index 63f2eda..3f7da53 100644 --- a/CSI-H238M/CSI-H238M/Views/MainWindow.xaml +++ b/CSI-H238M/CSI-H238M/Views/MainWindow.xaml @@ -2,6 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="CSI-H238M 高配版摩擦系数仪、摩擦系数测定仪" Height="800" Width="1024" + WindowStartupLocation="CenterScreen" + WindowState="Maximized" Background="#F0F3F5"> + + +