From 07c8bd92da54451d1c503f202afedee6dc6495b0 Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Fri, 30 Jan 2026 13:39:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CSI-H238M/CSI-H238M/Services/ModbusService.cs | 171 +++++++++++++++++- CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs | 57 +++--- CSI-H238M/CSI-H238M/Views/TestPage.xaml | 3 +- 3 files changed, 198 insertions(+), 33 deletions(-) diff --git a/CSI-H238M/CSI-H238M/Services/ModbusService.cs b/CSI-H238M/CSI-H238M/Services/ModbusService.cs index 840fd5f..3c480b7 100644 --- a/CSI-H238M/CSI-H238M/Services/ModbusService.cs +++ b/CSI-H238M/CSI-H238M/Services/ModbusService.cs @@ -442,10 +442,80 @@ namespace COFTester.Services } /// - /// 写入启动/停止寄存器 M31 + /// 触发测试启动按钮 M30(复归型) + /// M30 是复归型按钮,需要写入脉冲信号:true → 延迟 → false + /// 然后通过读取 M31 来判断测试是否真正开始(1=测试中,0=停止) + /// + public virtual async Task TriggerTestStartAsync() + { + try + { + if (_modbusMaster != null && _isConnected) + { + const ushort START_BUTTON_ADDRESS = 30; // M30 复归型按钮 + + System.Diagnostics.Debug.WriteLine($"[Modbus] 触发测试启动按钮 M{START_BUTTON_ADDRESS}"); + + // 写入 true(触发) + await _modbusMaster.WriteSingleCoilAsync(1, START_BUTTON_ADDRESS, true); + System.Diagnostics.Debug.WriteLine($"[Modbus] M{START_BUTTON_ADDRESS} = true"); + + // 延迟 100ms + await Task.Delay(100); + + // 写入 false(复位) + await _modbusMaster.WriteSingleCoilAsync(1, START_BUTTON_ADDRESS, false); + System.Diagnostics.Debug.WriteLine($"[Modbus] M{START_BUTTON_ADDRESS} = false"); + + // 延迟 100ms 确保 PLC 处理完成 + await Task.Delay(100); + + System.Diagnostics.Debug.WriteLine($"[Modbus] M{START_BUTTON_ADDRESS} 脉冲信号发送完成"); + } + } + catch (Exception ex) + { + OnErrorOccurred($"触发测试启动失败: {ex.Message}"); + System.Diagnostics.Debug.WriteLine($"[Modbus] 触发 M30 异常: {ex.Message}"); + throw; + } + } + + /// + /// 读取测试状态标记位 M31 + /// M31: 1=测试中,0=停止 + /// + /// true=测试中,false=停止 + public virtual async Task ReadTestStatusAsync() + { + try + { + if (_modbusMaster != null && _isConnected) + { + const ushort STATUS_FLAG_ADDRESS = 31; // M31 状态标记位 + + var coils = await _modbusMaster.ReadCoilsAsync(1, STATUS_FLAG_ADDRESS, 1); + bool isRunning = coils[0]; + + System.Diagnostics.Debug.WriteLine($"[Modbus] 读取测试状态 M{STATUS_FLAG_ADDRESS} = {(isRunning ? "1 (测试中)" : "0 (停止)")}"); + + return isRunning; + } + return false; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[Modbus] 读取 M31 状态异常: {ex.Message}"); + return false; + } + } + + /// + /// 写入启动/停止寄存器 M31(已弃用,请使用 TriggerTestStartAsync) /// M30 复归型, M31 标注为 1=开始,0=停止 /// /// 1=开始测试, 0=停止测试 + [Obsolete("请使用 TriggerTestStartAsync() 触发 M30,然后通过 ReadTestStatusAsync() 读取 M31 状态")] public virtual async Task WriteStartStopRegisterAsync(ushort value) { try @@ -649,6 +719,7 @@ namespace COFTester.Services /// 數據採集主循環 /// 正確流程:1. 寫入測試參數 → 2. 循環讀取數據(力值、位移、位置) /// 注意:不再發送 Start/Stop 命令,由方向控制(M0-M3)來控制運動 + /// M30 复归型按钮触发测试,M31 状态标记位(1=测试中,0=停止) /// protected override async Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token) { @@ -666,11 +737,30 @@ namespace COFTester.Services int totalPoints = (int)(parameters.TestDuration * parameters.SamplingRate); System.Diagnostics.Debug.WriteLine($"[ModbusTCP] 数据采集配置: {totalPoints} 点, 间隔 {intervalMs:F1}ms"); - System.Diagnostics.Debug.WriteLine($"[ModbusTCP] 注意:使用 M31=1 启动测试,M31=0 停止测试"); + System.Diagnostics.Debug.WriteLine($"[ModbusTCP] 监控 M31 状态:1=测试中,0=停止"); // 循环读取传感器数据(包含力值、位移和位置) for (int i = 0; i < totalPoints && !token.IsCancellationRequested; i++) { + // 每隔一定次数检查 M31 状态(避免频繁读取) + if (i % 10 == 0) // 每 10 个数据点检查一次 + { + try + { + bool isTestRunning = await ReadTestStatusAsync(); + if (!isTestRunning) + { + System.Diagnostics.Debug.WriteLine("[ModbusTCP] M31 = 0,PLC 已停止测试"); + break; // 退出采集循环 + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[ModbusTCP] 读取 M31 状态失败: {ex.Message}"); + // 读取失败不影响数据采集,继续执行 + } + } + // 读取力值和位移 var dataPoint = await ReadSensorDataAsync(); @@ -707,7 +797,16 @@ namespace COFTester.Services finally { _isAcquiring = false; - System.Diagnostics.Debug.WriteLine("[ModbusTCP] 數據採集結束(不再發送 Stop 命令)"); + System.Diagnostics.Debug.WriteLine("[ModbusTCP] 數據採集結束"); + + // 最后再检查一次 M31 状态 + try + { + bool isTestRunning = await ReadTestStatusAsync(); + System.Diagnostics.Debug.WriteLine($"[ModbusTCP] 采集结束时 M31 = {(isTestRunning ? "1 (测试中)" : "0 (停止)")}"); + } + catch { } + OnTestFinished(); } } @@ -1106,6 +1205,7 @@ namespace COFTester.Services /// 數據採集主循環 /// 正確流程:1. 寫入測試參數 → 2. 循環讀取數據(力值、位移、位置) /// 注意:不再發送 Start/Stop 命令,由方向控制(M0-M3)來控制運動 + /// M30 复归型按钮触发测试,M31 状态标记位(1=测试中,0=停止) /// protected override async Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token) { @@ -1123,11 +1223,30 @@ namespace COFTester.Services int totalPoints = (int)(parameters.TestDuration * parameters.SamplingRate); System.Diagnostics.Debug.WriteLine($"[ModbusRTU] 数据采集配置: {totalPoints} 点, 间隔 {intervalMs:F1}ms"); - System.Diagnostics.Debug.WriteLine($"[ModbusRTU] 注意:使用 M31=1 启动测试,M31=0 停止测试"); + System.Diagnostics.Debug.WriteLine($"[ModbusRTU] 监控 M31 状态:1=测试中,0=停止"); // 循环读取传感器数据(包含力值、位移和位置) for (int i = 0; i < totalPoints && !token.IsCancellationRequested; i++) { + // 每隔一定次数检查 M31 状态(避免频繁读取) + if (i % 10 == 0) // 每 10 个数据点检查一次 + { + try + { + bool isTestRunning = await ReadTestStatusAsync(); + if (!isTestRunning) + { + System.Diagnostics.Debug.WriteLine("[ModbusRTU] M31 = 0,PLC 已停止测试"); + break; // 退出采集循环 + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[ModbusRTU] 读取 M31 状态失败: {ex.Message}"); + // 读取失败不影响数据采集,继续执行 + } + } + // 读取力值和位移 var dataPoint = await ReadSensorDataAsync(); @@ -1164,7 +1283,16 @@ namespace COFTester.Services finally { _isAcquiring = false; - System.Diagnostics.Debug.WriteLine("[ModbusRTU] 數據採集結束(不再發送 Stop 命令)"); + System.Diagnostics.Debug.WriteLine("[ModbusRTU] 數據採集結束"); + + // 最后再检查一次 M31 状态 + try + { + bool isTestRunning = await ReadTestStatusAsync(); + System.Diagnostics.Debug.WriteLine($"[ModbusRTU] 采集结束时 M31 = {(isTestRunning ? "1 (测试中)" : "0 (停止)")}"); + } + catch { } + OnTestFinished(); } } @@ -1547,6 +1675,7 @@ namespace COFTester.Services /// 數據採集主循環 /// 正確流程:1. 寫入測試參數 → 2. 循環讀取數據(力值、位移、位置) /// 注意:不再發送 Start/Stop 命令,由方向控制(M0-M3)來控制運動 + /// M30 复归型按钮触发测试,M31 状态标记位(1=测试中,0=停止) /// protected override async Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token) { @@ -1563,11 +1692,30 @@ namespace COFTester.Services int totalPoints = (int)(parameters.TestDuration * parameters.SamplingRate); System.Diagnostics.Debug.WriteLine($"[ModbusASCII] 数据采集配置: {totalPoints} 点, 间隔 {intervalMs:F1}ms"); - System.Diagnostics.Debug.WriteLine($"[ModbusASCII] 注意:使用 M31=1 启动测试,M31=0 停止测试"); + System.Diagnostics.Debug.WriteLine($"[ModbusASCII] 监控 M31 状态:1=测试中,0=停止"); // 循环读取传感器数据(包含力值、位移和位置) for (int i = 0; i < totalPoints && !token.IsCancellationRequested; i++) { + // 每隔一定次数检查 M31 状态(避免频繁读取) + if (i % 10 == 0) // 每 10 个数据点检查一次 + { + try + { + bool isTestRunning = await ReadTestStatusAsync(); + if (!isTestRunning) + { + System.Diagnostics.Debug.WriteLine("[ModbusASCII] M31 = 0,PLC 已停止测试"); + break; // 退出采集循环 + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[ModbusASCII] 读取 M31 状态失败: {ex.Message}"); + // 读取失败不影响数据采集,继续执行 + } + } + // 读取力值和位移 var dataPoint = await ReadSensorDataAsync(); @@ -1604,7 +1752,16 @@ namespace COFTester.Services finally { _isAcquiring = false; - System.Diagnostics.Debug.WriteLine("[ModbusASCII] 数据采集结束(不再发送 Stop 命令)"); + System.Diagnostics.Debug.WriteLine("[ModbusASCII] 数据采集结束"); + + // 最后再检查一次 M31 状态 + try + { + bool isTestRunning = await ReadTestStatusAsync(); + System.Diagnostics.Debug.WriteLine($"[ModbusASCII] 采集结束时 M31 = {(isTestRunning ? "1 (测试中)" : "0 (停止)")}"); + } + catch { } + OnTestFinished(); } } diff --git a/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs b/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs index 0b43b29..0b7d6d7 100644 --- a/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs +++ b/CSI-H238M/CSI-H238M/ViewModels/ViewModel.cs @@ -640,16 +640,40 @@ namespace COFTester.ViewModels StatusMessage = $"开始测试 - {_selectedDirection}方向"; UpdateScottPlot(); - // M30 复归型 M31标注为 1开始,0停止 - // 向 M31 写入 1 开始测试 + // M30 复归型按钮,M31 状态标记位(1=测试中,0=停止) + // 向 M30 写入复归型脉冲来触发测试启动 if (_daqService is ModbusServiceBase modbusService) { Task.Run(async () => { try { - await modbusService.WriteStartStopRegisterAsync(1); // M31 = 1 开始 - System.Diagnostics.Debug.WriteLine("[ViewModel] M31 = 1 (开始测试)"); + // 触发 M30 复归型按钮 + await modbusService.TriggerTestStartAsync(); + System.Diagnostics.Debug.WriteLine("[ViewModel] M30 脉冲已发送(触发测试启动)"); + + // 等待一小段时间让 PLC 处理 + await Task.Delay(200); + + // 读取 M31 确认测试是否真正开始 + bool isTestRunning = await modbusService.ReadTestStatusAsync(); + + Application.Current?.Dispatcher.InvokeAsync(() => + { + if (isTestRunning) + { + System.Diagnostics.Debug.WriteLine("[ViewModel] M31 = 1,测试已启动"); + StatusMessage = "测试已启动"; + } + else + { + System.Diagnostics.Debug.WriteLine("[ViewModel] M31 = 0,测试未启动"); + StatusMessage = "测试启动失败,请检查设备"; + // 启动失败时恢复按钮状态 + IsTesting = false; + TestButtonText = Lang.StartTest; + } + }); } catch (Exception ex) { @@ -670,31 +694,16 @@ namespace COFTester.ViewModels private void StopTest() { - // M30 复归型 M31标注为 1开始,0停止 - // 向 M31 写入 0 停止测试 - if (_daqService is ModbusServiceBase modbusService) - { - Task.Run(async () => - { - try - { - await modbusService.WriteStartStopRegisterAsync(0); // M31 = 0 停止 - System.Diagnostics.Debug.WriteLine("[ViewModel] M31 = 0 (停止测试)"); - } - catch (Exception ex) - { - Application.Current?.Dispatcher.InvokeAsync(() => - { - StatusMessage = $"停止测试失败: {ex.Message}"; - }); - } - }); - } + // M30 复归型按钮,M31 状态标记位(1=测试中,0=停止) + // M31 是只读状态位,由 PLC 控制,我们只需停止数据采集 + // PLC 会自动将 M31 设置为 0 _daqService.StopAcquisition(); IsTesting = false; TestButtonText = Lang.StartTest; // 恢复按钮文本为"开始测试" StatusMessage = Lang.TestStopped; + + System.Diagnostics.Debug.WriteLine("[ViewModel] 停止测试,等待 PLC 将 M31 设置为 0"); } private async void Reset() diff --git a/CSI-H238M/CSI-H238M/Views/TestPage.xaml b/CSI-H238M/CSI-H238M/Views/TestPage.xaml index 763358b..cd97cd3 100644 --- a/CSI-H238M/CSI-H238M/Views/TestPage.xaml +++ b/CSI-H238M/CSI-H238M/Views/TestPage.xaml @@ -257,8 +257,7 @@