This commit is contained in:
GukSang.Jin
2026-01-29 12:39:17 +08:00
parent ead1b99aa8
commit 70f8a2b8de
8 changed files with 398 additions and 1 deletions

View File

@@ -174,6 +174,9 @@ namespace COFTester.Models
public ushort TestStrokeRegister { get; set; } = 26; // 測試行程 (mm)Float2個寄存器 public ushort TestStrokeRegister { get; set; } = 26; // 測試行程 (mm)Float2個寄存器
public ushort SamplingRateRegister { get; set; } = 28; // 採樣頻率 (Hz)Float2個寄存器 public ushort SamplingRateRegister { get; set; } = 28; // 採樣頻率 (Hz)Float2個寄存器
// === 校準寄存器(寫入)===
public ushort CalibrationRegister { get; set; } = 1300; // 校準命令寄存器 M1300
public int RetryCount { get; set; } = 3; // 重試次數 public int RetryCount { get; set; } = 3; // 重試次數
public int RetryDelay { get; set; } = 500; // 重試延遲(毫秒) public int RetryDelay { get; set; } = 500; // 重試延遲(毫秒)
} }
@@ -208,6 +211,9 @@ namespace COFTester.Models
public ushort TestStrokeRegister { get; set; } = 26; // 測試行程 (mm)Float2個寄存器 public ushort TestStrokeRegister { get; set; } = 26; // 測試行程 (mm)Float2個寄存器
public ushort SamplingRateRegister { get; set; } = 28; // 採樣頻率 (Hz)Float2個寄存器 public ushort SamplingRateRegister { get; set; } = 28; // 採樣頻率 (Hz)Float2個寄存器
// === 校準寄存器(寫入)===
public ushort CalibrationRegister { get; set; } = 1300; // 校準命令寄存器 M1300
public int RetryCount { get; set; } = 3; public int RetryCount { get; set; } = 3;
public int RetryDelay { get; set; } = 500; public int RetryDelay { get; set; } = 500;
} }

View File

@@ -338,6 +338,22 @@ namespace COFTester.Models
void StartAcquisition(TestParameters parameters); void StartAcquisition(TestParameters parameters);
void StopAcquisition(); void StopAcquisition();
void ResetSensors(); void ResetSensors();
/// <summary>
/// 零點標定
/// </summary>
void ZeroCalibration();
/// <summary>
/// 拉力校準
/// </summary>
void ForceCalibration();
/// <summary>
/// 復歸
/// </summary>
void ReturnToOrigin();
bool IsConnected { get; } bool IsConnected { get; }
} }

View File

@@ -130,6 +130,10 @@ namespace COFTester.Resources
["CalibrationInstruction"] = "请确保设备已连接,然后执行以下标定步骤:", ["CalibrationInstruction"] = "请确保设备已连接,然后执行以下标定步骤:",
["ZeroCalibration"] = "零点标定", ["ZeroCalibration"] = "零点标定",
["ZeroCalibrationNote"] = "说明:在无负载状态下执行零点标定,将当前读数设为零点。", ["ZeroCalibrationNote"] = "说明:在无负载状态下执行零点标定,将当前读数设为零点。",
["ForceCalibration"] = "拉力校准",
["ForceCalibrationNote"] = "说明:在已知标准负载下执行拉力校准,校准传感器精度。",
["ReturnToOrigin"] = "复归",
["ReturnToOriginNote"] = "说明:将设备返回到初始位置。",
// 测试参数标签 // 测试参数标签
["SpeedLabel"] = "速度:", ["SpeedLabel"] = "速度:",
@@ -271,6 +275,10 @@ namespace COFTester.Resources
["CalibrationInstruction"] = "Please ensure the device is connected, then perform the following calibration steps:", ["CalibrationInstruction"] = "Please ensure the device is connected, then perform the following calibration steps:",
["ZeroCalibration"] = "Zero Calibration", ["ZeroCalibration"] = "Zero Calibration",
["ZeroCalibrationNote"] = "Note: Perform zero calibration under no-load condition to set the current reading as zero point.", ["ZeroCalibrationNote"] = "Note: Perform zero calibration under no-load condition to set the current reading as zero point.",
["ForceCalibration"] = "Force Calibration",
["ForceCalibrationNote"] = "Note: Perform force calibration under known standard load to calibrate sensor accuracy.",
["ReturnToOrigin"] = "Return to Origin",
["ReturnToOriginNote"] = "Note: Return the device to the initial position.",
// Test Parameter Labels // Test Parameter Labels
["SpeedLabel"] = "Speed:", ["SpeedLabel"] = "Speed:",
@@ -406,6 +414,10 @@ namespace COFTester.Resources
public string CalibrationInstruction => GetString("CalibrationInstruction"); public string CalibrationInstruction => GetString("CalibrationInstruction");
public string ZeroCalibration => GetString("ZeroCalibration"); public string ZeroCalibration => GetString("ZeroCalibration");
public string ZeroCalibrationNote => GetString("ZeroCalibrationNote"); public string ZeroCalibrationNote => GetString("ZeroCalibrationNote");
public string ForceCalibration => GetString("ForceCalibration");
public string ForceCalibrationNote => GetString("ForceCalibrationNote");
public string ReturnToOrigin => GetString("ReturnToOrigin");
public string ReturnToOriginNote => GetString("ReturnToOriginNote");
// Test Parameter Labels // Test Parameter Labels
public string SpeedLabel => GetString("SpeedLabel"); public string SpeedLabel => GetString("SpeedLabel");
@@ -542,6 +554,10 @@ namespace COFTester.Resources
OnPropertyChanged(nameof(CalibrationInstruction)); OnPropertyChanged(nameof(CalibrationInstruction));
OnPropertyChanged(nameof(ZeroCalibration)); OnPropertyChanged(nameof(ZeroCalibration));
OnPropertyChanged(nameof(ZeroCalibrationNote)); OnPropertyChanged(nameof(ZeroCalibrationNote));
OnPropertyChanged(nameof(ForceCalibration));
OnPropertyChanged(nameof(ForceCalibrationNote));
OnPropertyChanged(nameof(ReturnToOrigin));
OnPropertyChanged(nameof(ReturnToOriginNote));
// Test Parameter Labels // Test Parameter Labels
OnPropertyChanged(nameof(SpeedLabel)); OnPropertyChanged(nameof(SpeedLabel));

View File

@@ -22,6 +22,21 @@ namespace COFTester.Services
Reset = 2 Reset = 2
} }
/// <summary>
/// Modbus 校準命令枚舉(寄存器 M1300
/// </summary>
public enum ModbusCalibrationCommand : ushort
{
/// <summary>無操作</summary>
None = 0,
/// <summary>零點標定</summary>
ZeroCalibration = 1,
/// <summary>拉力校準</summary>
ForceCalibration = 2,
/// <summary>復歸</summary>
Return = 3
}
/// <summary> /// <summary>
/// Modbus 設備狀態枚舉 /// Modbus 設備狀態枚舉
/// </summary> /// </summary>
@@ -139,10 +154,72 @@ namespace COFTester.Services
} }
} }
/// <summary>
/// 零點標定,向 M1300 寫入命令 1
/// </summary>
public virtual void ZeroCalibration()
{
try
{
if (_modbusMaster != null && _isConnected)
{
System.Diagnostics.Debug.WriteLine("[Modbus] 發送零點標定命令 (1) 到 M1300");
WriteCalibrationRegisterAsync((ushort)ModbusCalibrationCommand.ZeroCalibration).Wait();
}
}
catch (Exception ex)
{
OnErrorOccurred($"零點標定失敗: {ex.Message}");
}
}
/// <summary>
/// 拉力校準,向 M1300 寫入命令 2
/// </summary>
public virtual void ForceCalibration()
{
try
{
if (_modbusMaster != null && _isConnected)
{
System.Diagnostics.Debug.WriteLine("[Modbus] 發送拉力校準命令 (2) 到 M1300");
WriteCalibrationRegisterAsync((ushort)ModbusCalibrationCommand.ForceCalibration).Wait();
}
}
catch (Exception ex)
{
OnErrorOccurred($"拉力校準失敗: {ex.Message}");
}
}
/// <summary>
/// 復歸,向 M1300 寫入命令 3
/// </summary>
public virtual void ReturnToOrigin()
{
try
{
if (_modbusMaster != null && _isConnected)
{
System.Diagnostics.Debug.WriteLine("[Modbus] 發送復歸命令 (3) 到 M1300");
WriteCalibrationRegisterAsync((ushort)ModbusCalibrationCommand.Return).Wait();
}
}
catch (Exception ex)
{
OnErrorOccurred($"復歸失敗: {ex.Message}");
}
}
protected abstract Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token); protected abstract Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token);
protected abstract Task<TestDataPoint?> ReadSensorDataAsync(); protected abstract Task<TestDataPoint?> ReadSensorDataAsync();
protected abstract Task WriteControlRegisterAsync(ushort value); protected abstract Task WriteControlRegisterAsync(ushort value);
/// <summary>
/// 寫入校準命令到 M1300 寄存器
/// </summary>
protected abstract Task WriteCalibrationRegisterAsync(ushort value);
/// <summary> /// <summary>
/// 寫入測試參數到 PLC 寄存器 /// 寫入測試參數到 PLC 寄存器
/// </summary> /// </summary>
@@ -392,6 +469,23 @@ namespace COFTester.Services
} }
} }
/// <summary>
/// 寫入校準命令到 M1300
/// 0 = 無操作
/// 1 = 零點標定
/// 2 = 拉力校準
/// 3 = 復歸
/// </summary>
protected override async Task WriteCalibrationRegisterAsync(ushort value)
{
if (_modbusMaster != null)
{
await _modbusMaster.WriteSingleRegisterAsync(
_config.SlaveId, _config.CalibrationRegister, value);
System.Diagnostics.Debug.WriteLine($"[ModbusTCP] 校準寄存器[{_config.CalibrationRegister}] = {value}");
}
}
/// <summary> /// <summary>
/// 寫入測試參數到 PLC 寄存器 /// 寫入測試參數到 PLC 寄存器
/// 參數映射: /// 參數映射:
@@ -674,6 +768,23 @@ namespace COFTester.Services
} }
} }
/// <summary>
/// 寫入校準命令到 M1300
/// 0 = 無操作
/// 1 = 零點標定
/// 2 = 拉力校準
/// 3 = 復歸
/// </summary>
protected override async Task WriteCalibrationRegisterAsync(ushort value)
{
if (_modbusMaster != null)
{
await _modbusMaster.WriteSingleRegisterAsync(
_config.SlaveId, _config.CalibrationRegister, value);
System.Diagnostics.Debug.WriteLine($"[ModbusRTU] 校準寄存器[{_config.CalibrationRegister}] = {value}");
}
}
/// <summary> /// <summary>
/// 寫入測試參數到 PLC 寄存器 /// 寫入測試參數到 PLC 寄存器
/// </summary> /// </summary>
@@ -957,6 +1068,19 @@ namespace COFTester.Services
} }
} }
/// <summary>
/// 寫入校準命令到 M1300
/// </summary>
protected override async Task WriteCalibrationRegisterAsync(ushort value)
{
if (_modbusMaster != null)
{
await _modbusMaster.WriteSingleRegisterAsync(
_config.SlaveId, _config.CalibrationRegister, value);
System.Diagnostics.Debug.WriteLine($"[ModbusASCII] 校準寄存器[{_config.CalibrationRegister}] = {value}");
}
}
/// <summary> /// <summary>
/// 寫入測試參數到 PLC 寄存器 /// 寫入測試參數到 PLC 寄存器
/// </summary> /// </summary>
@@ -1164,6 +1288,51 @@ namespace COFTester.Services
} }
} }
public void ZeroCalibration()
{
try
{
if (_serialPort != null && _isConnected)
{
_serialPort.WriteLine("ZERO_CAL");
}
}
catch (Exception ex)
{
OnErrorOccurred($"零點標定失败: {ex.Message}");
}
}
public void ForceCalibration()
{
try
{
if (_serialPort != null && _isConnected)
{
_serialPort.WriteLine("FORCE_CAL");
}
}
catch (Exception ex)
{
OnErrorOccurred($"拉力校準失败: {ex.Message}");
}
}
public void ReturnToOrigin()
{
try
{
if (_serialPort != null && _isConnected)
{
_serialPort.WriteLine("RETURN");
}
}
catch (Exception ex)
{
OnErrorOccurred($"復歸失败: {ex.Message}");
}
}
private async Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token) private async Task AcquisitionLoopAsync(TestParameters parameters, CancellationToken token)
{ {
try try

View File

@@ -511,5 +511,23 @@ namespace COFTester.Services
{ {
// 模擬傳感器清零(無實際操作) // 模擬傳感器清零(無實際操作)
} }
public void ZeroCalibration()
{
// 模擬零點標定(無實際操作)
System.Diagnostics.Debug.WriteLine("[Simulated] 零點標定完成");
}
public void ForceCalibration()
{
// 模擬拉力校準(無實際操作)
System.Diagnostics.Debug.WriteLine("[Simulated] 拉力校準完成");
}
public void ReturnToOrigin()
{
// 模擬復歸(無實際操作)
System.Diagnostics.Debug.WriteLine("[Simulated] 復歸完成");
}
} }
} }

View File

@@ -67,6 +67,11 @@ namespace COFTester.ViewModels
ClearAllTestsCommand = new RelayCommand(ClearAllTests, () => !_isTesting && TestRecords?.Count > 0); ClearAllTestsCommand = new RelayCommand(ClearAllTests, () => !_isTesting && TestRecords?.Count > 0);
GenerateReportCommand = new RelayCommand(GenerateReport, () => TestRecords?.Count > 0); GenerateReportCommand = new RelayCommand(GenerateReport, () => TestRecords?.Count > 0);
// 校準命令
ZeroCalibrationCommand = new RelayCommand(ZeroCalibration, () => !_isTesting && IsConnected);
ForceCalibrationCommand = new RelayCommand(ForceCalibration, () => !_isTesting && IsConnected);
ReturnToOriginCommand = new RelayCommand(ReturnToOrigin, () => !_isTesting && IsConnected);
Parameters = _config.DefaultTestParameters ?? new TestParameters(); Parameters = _config.DefaultTestParameters ?? new TestParameters();
TestRecords = new ObservableCollection<TestResult>(); TestRecords = new ObservableCollection<TestResult>();
TestRecords.CollectionChanged += (s, e) => TestRecords.CollectionChanged += (s, e) =>
@@ -418,6 +423,11 @@ namespace COFTester.ViewModels
public ICommand OpenConfigCommand { get; } public ICommand OpenConfigCommand { get; }
public ICommand ClearAllTestsCommand { get; } public ICommand ClearAllTestsCommand { get; }
public ICommand GenerateReportCommand { get; } public ICommand GenerateReportCommand { get; }
// 校準命令
public ICommand ZeroCalibrationCommand { get; }
public ICommand ForceCalibrationCommand { get; }
public ICommand ReturnToOriginCommand { get; }
#endregion #endregion
#region Event Handlers #region Event Handlers
@@ -622,6 +632,111 @@ namespace COFTester.ViewModels
_daqService.ResetSensors(); _daqService.ResetSensors();
} }
/// <summary>
/// 零點標定 - 向 M1300 寫入命令 1
/// </summary>
private void ZeroCalibration()
{
try
{
if (!IsConnected)
{
StatusMessage = "请先连接设备";
MessageBox.Show("请先连接设备后再执行零点标定", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
StatusMessage = "正在执行零点标定...";
_daqService.ZeroCalibration();
StatusMessage = "零点标定完成";
System.Diagnostics.Debug.WriteLine("[ViewModel] 零点标定命令已发送");
MessageBox.Show("零点标定完成!\n\n当前读数已设为零点。",
"标定成功",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
StatusMessage = $"零点标定失败: {ex.Message}";
MessageBox.Show($"零点标定时发生错误:\n{ex.Message}",
"错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
/// <summary>
/// 拉力校准 - 向 M1300 写入命令 2
/// </summary>
private void ForceCalibration()
{
try
{
if (!IsConnected)
{
StatusMessage = "请先连接设备";
MessageBox.Show("请先连接设备后再执行拉力校准", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
StatusMessage = "正在执行拉力校准...";
_daqService.ForceCalibration();
StatusMessage = "拉力校准完成";
System.Diagnostics.Debug.WriteLine("[ViewModel] 拉力校准命令已发送");
MessageBox.Show("拉力校准完成!\n\n传感器已校准。",
"校准成功",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
StatusMessage = $"拉力校准失败: {ex.Message}";
MessageBox.Show($"拉力校准时发生错误:\n{ex.Message}",
"错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
/// <summary>
/// 复归 - 向 M1300 写入命令 3
/// </summary>
private void ReturnToOrigin()
{
try
{
if (!IsConnected)
{
StatusMessage = "请先连接设备";
MessageBox.Show("请先连接设备后再执行复归", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
StatusMessage = "正在执行复归...";
_daqService.ReturnToOrigin();
StatusMessage = "复归完成";
System.Diagnostics.Debug.WriteLine("[ViewModel] 复归命令已发送");
MessageBox.Show("复归完成!\n\n设备已返回原点。",
"复归成功",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
StatusMessage = $"复归失败: {ex.Message}";
MessageBox.Show($"复归时发生错误:\n{ex.Message}",
"错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
/// <summary> /// <summary>
/// 添加曲线到图表 /// 添加曲线到图表
/// </summary> /// </summary>

View File

@@ -71,7 +71,8 @@
<TextBlock Text="{Binding Lang.CalibrationOperation}" FontWeight="Bold" Margin="0,0,0,10" FontSize="14"/> <TextBlock Text="{Binding Lang.CalibrationOperation}" FontWeight="Bold" Margin="0,0,0,10" FontSize="14"/>
<TextBlock Text="{Binding Lang.CalibrationInstruction}" TextWrapping="Wrap" Margin="0,0,0,15" FontSize="12"/> <TextBlock Text="{Binding Lang.CalibrationInstruction}" TextWrapping="Wrap" Margin="0,0,0,15" FontSize="12"/>
<Button Content="{Binding Lang.ZeroCalibration}" Command="{Binding ResetCommand}" Height="50" Foreground="White" FontSize="14" Margin="0,0,0,10"> <!-- 零点标定 -->
<Button Content="{Binding Lang.ZeroCalibration}" Command="{Binding ZeroCalibrationCommand}" Height="50" Foreground="White" FontSize="14" Margin="0,0,0,10">
<Button.Style> <Button.Style>
<Style TargetType="Button"> <Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource AccentBrush}"/> <Setter Property="Background" Value="{StaticResource AccentBrush}"/>
@@ -95,6 +96,60 @@
</Button> </Button>
<TextBlock Text="{Binding Lang.ZeroCalibrationNote}" <TextBlock Text="{Binding Lang.ZeroCalibrationNote}"
TextWrapping="Wrap" FontSize="11" Foreground="{StaticResource GrayBrush}" Margin="0,0,0,15"/>
<!-- 拉力校准 -->
<Button Content="{Binding Lang.ForceCalibration}" Command="{Binding ForceCalibrationCommand}" Height="50" Foreground="White" FontSize="14" Margin="0,0,0,10">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource SuccessBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
CornerRadius="8"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
<TextBlock Text="{Binding Lang.ForceCalibrationNote}"
TextWrapping="Wrap" FontSize="11" Foreground="{StaticResource GrayBrush}" Margin="0,0,0,15"/>
<!-- 复归 -->
<Button Content="{Binding Lang.ReturnToOrigin}" Command="{Binding ReturnToOriginCommand}" Height="50" Foreground="White" FontSize="14" Margin="0,0,0,10">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#95A5A6"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
CornerRadius="8"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
<TextBlock Text="{Binding Lang.ReturnToOriginNote}"
TextWrapping="Wrap" FontSize="11" Foreground="{StaticResource GrayBrush}" Margin="0,5,0,0"/> TextWrapping="Wrap" FontSize="11" Foreground="{StaticResource GrayBrush}" Margin="0,5,0,0"/>
</StackPanel> </StackPanel>
</Border> </Border>

View File

@@ -15,6 +15,7 @@
"TestDurationRegister": 24, "TestDurationRegister": 24,
"TestStrokeRegister": 26, "TestStrokeRegister": 26,
"SamplingRateRegister": 28, "SamplingRateRegister": 28,
"CalibrationRegister": 1300,
"RetryCount": 3, "RetryCount": 3,
"RetryDelay": 500 "RetryDelay": 500
}, },
@@ -37,6 +38,7 @@
"TestDurationRegister": 24, "TestDurationRegister": 24,
"TestStrokeRegister": 26, "TestStrokeRegister": 26,
"SamplingRateRegister": 28, "SamplingRateRegister": 28,
"CalibrationRegister": 1300,
"RetryCount": 3, "RetryCount": 3,
"RetryDelay": 500 "RetryDelay": 500
}, },