diff --git a/Models/PlcConfiguration.cs b/Models/PlcConfiguration.cs index 3ad90ed..a72d46c 100644 --- a/Models/PlcConfiguration.cs +++ b/Models/PlcConfiguration.cs @@ -31,6 +31,7 @@ public ushort FriabilityRpm { get; set; } public ushort FriabilityRounds { get; set; } public ushort FriabilityRoundsBox { get; set; } // 兼容旧配置字段 + public ushort FriabilityRealtimeRounds { get; set; } public ushort FriabilityTestTime { get; set; } public ushort FriabilityWeightBefore { get; set; } public ushort FriabilityWeightAfter { get; set; } diff --git a/Services/PlcSimulator.cs b/Services/PlcSimulator.cs index 87e6380..c870b4d 100644 --- a/Services/PlcSimulator.cs +++ b/Services/PlcSimulator.cs @@ -24,6 +24,7 @@ namespace TabletTester2025.Services 414 => 4.9f + (float)_rand.NextDouble() * 2, // 后重 416 => 1.0f, // 失重率% 300 => 100.0f, // 硬度加压速度(mm/min) + 330 => 31.0f, // 崩解升降频次(次/min) 340 => 50f, // 溶出速度1(r/min) 350 => 50f, // 溶出速度2(r/min) 400 => 50 + (float)_rand.NextDouble() * 30, // 转速 @@ -40,6 +41,7 @@ namespace TabletTester2025.Services { int value = startAddress switch { + 82 => _rand.Next(0, 101), // 脆碎实时圈数 410 => 100, // 脆碎圈数 430 => 30, // 溶出1时间(min) 440 => 30, // 溶出2时间(min) diff --git a/ViewModels/StationViewModel.cs b/ViewModels/StationViewModel.cs index 6c3f655..d11e456 100644 --- a/ViewModels/StationViewModel.cs +++ b/ViewModels/StationViewModel.cs @@ -149,6 +149,7 @@ namespace TabletTester2025.ViewModels [ObservableProperty] private bool _friabilityClockwise = true; [ObservableProperty] private bool _friabilityCounterClockwise; [ObservableProperty] private double _friabilityCurrentRpm; + [ObservableProperty] private int _friabilityRealtimeRounds; [ObservableProperty] private int _friabilityRemainingRounds = 100; public IAsyncRelayCommand StopHardnessCommand { get; } public IAsyncRelayCommand StopFriabilityCommand { get; } @@ -1888,6 +1889,7 @@ namespace TabletTester2025.ViewModels int totalRounds = Math.Max(1, FriabilityTargetRounds); FriabilityRemainingRounds = totalRounds; FriabilityCurrentRpm = rpm; + await RefreshFriabilityRealtimeRoundsAsync(); await PulseCoilAsync(startCoil); int durationMs = (int)Math.Ceiling(testTimeMin * 60 * 1000); // 总运行时间(毫秒) @@ -1904,6 +1906,8 @@ namespace TabletTester2025.ViewModels // 更新界面绑定的剩余圈数 FriabilityRemainingRounds = remainingRounds; + if (i % 500 == 0) + await RefreshFriabilityRealtimeRoundsAsync(); // 等待100ms,再更新下一次 await Task.Delay(100); @@ -1914,6 +1918,7 @@ namespace TabletTester2025.ViewModels double weightAfter = await ReadFriabilityWeightAsync(ResolveFriabilityWeightAfterRegister(), "脆碎后重量"); SetFriabilityWeightFromPlc(weightAfter: weightAfter); FriabilityCurrentRpm = rpm; + await RefreshFriabilityRealtimeRoundsAsync(); bool localLossReady = TryCalculateFriabilityLossFromWeights(out double localLossPercent); if (localLossReady) @@ -1962,6 +1967,31 @@ namespace TabletTester2025.ViewModels return value; } + private ushort ResolveFriabilityRealtimeRoundsRegister() + { + return _plcConfig.FriabilityRealtimeRounds != 0 + ? _plcConfig.FriabilityRealtimeRounds + : (ushort)82; + } + + private async Task RefreshFriabilityRealtimeRoundsAsync() + { + ushort registerAddress = ResolveFriabilityRealtimeRoundsRegister(); + if (registerAddress == 0) + return; + + try + { + int value = await _plc.ReadIntAsync(registerAddress); + if (value >= 0) + FriabilityRealtimeRounds = value; + } + catch + { + // Keep the last displayed realtime count if the PLC read fails once. + } + } + private async Task RunDisintegrationAsync() { if (_isDisintegrationRunning) return; diff --git a/Views/MainWindow.xaml b/Views/MainWindow.xaml index 64b55df..84c297c 100644 --- a/Views/MainWindow.xaml +++ b/Views/MainWindow.xaml @@ -474,10 +474,6 @@ - - - - @@ -494,7 +490,13 @@ - + + + + + + + diff --git a/Views/SettingsWindow.xaml b/Views/SettingsWindow.xaml index 83b7c2f..b0fc281 100644 --- a/Views/SettingsWindow.xaml +++ b/Views/SettingsWindow.xaml @@ -130,6 +130,10 @@ + + + + diff --git a/Views/SettingsWindow.xaml.cs b/Views/SettingsWindow.xaml.cs index d41ea57..33b0e96 100644 --- a/Views/SettingsWindow.xaml.cs +++ b/Views/SettingsWindow.xaml.cs @@ -26,6 +26,9 @@ namespace TabletTester2025 await LoadPlcFloatToTextBoxAsync(ResolveFriabilityRpmRegister(), FriabilityRpmBox); await LoadPlcIntToTextBoxAsync(ResolveFriabilityRoundsRegister(), FriabilityRoundsBox); + // 崩解 + await LoadPlcFloatToTextBoxAsync(ResolveDisintegrationSpeedRegister(), DisintegrationSpeedBox); + // 溶出度 await LoadPlcFloatToTextBoxAsync(ResolveDissolution1SpeedRegister(), Dissolution1SpeedBox); await LoadPlcFloatToTextBoxAsync(ResolveDissolution2SpeedRegister(), Dissolution2SpeedBox); @@ -44,6 +47,7 @@ namespace TabletTester2025 FriabilityRoundsBox.Text = ResolveFriabilityTargetRounds(p).ToString(); FriabilityMaxLossBox.Text = p.FriabilityMaxLossPercent.ToString(); DisintegrationTimeMinBox.Text = ResolveDisintegrationTimeMin(p).ToString("0.###"); + DisintegrationSpeedBox.Text = p.DisintegrationSpeedRpm.ToString("0.###"); //DisintegrationTempBox.Text = p.DisintegrationTemperatureC.ToString(); //DissolutionTempBox.Text = p.DissolutionTemperatureC.ToString(); Dissolution1TimeBox.Text = p.Dissolution1TimeMin.ToString(); @@ -82,6 +86,8 @@ namespace TabletTester2025 p.FriabilityTargetRounds = ParsePositiveInt(FriabilityRoundsBox.Text, "脆碎圈数"); p.FriabilityMaxLossPercent = ParseFiniteDouble(FriabilityMaxLossBox.Text, "最大失重率"); double disintegrationTimeMin = ParsePositiveDouble(DisintegrationTimeMinBox.Text, "崩解时间"); + double disintegrationSpeed = ParsePositiveDouble(DisintegrationSpeedBox.Text, "升降频次"); + p.DisintegrationSpeedRpm = disintegrationSpeed; p.DisintegrationMaxSeconds = ToDisintegrationSeconds(disintegrationTimeMin); //p.DisintegrationTemperatureC = ParseFiniteDouble(DisintegrationTempBox.Text, "崩解介质温度"); //p.DissolutionTemperatureC = ParseFiniteDouble(DissolutionTempBox.Text, "溶出介质温度"); @@ -98,6 +104,7 @@ namespace TabletTester2025 await WriteHardnessDamageThresholdAsync(hardnessDamageThreshold); await WriteFriabilityRpmAsync(friabilityRpm); await WriteDisintegrationTimeAsync(disintegrationTimeMin); + await WriteDisintegrationSpeedAsync(disintegrationSpeed); await WriteDissolution1SpeedAsync(dissolution1Speed); await WriteDissolution2SpeedAsync(dissolution2Speed); await WriteDissolution1TimeAsync(p.Dissolution1TimeMin); @@ -329,6 +336,11 @@ namespace TabletTester2025 return App.PlcConfig.DisintegrationTime != 0 ? App.PlcConfig.DisintegrationTime : (ushort)420; } + private static ushort ResolveDisintegrationSpeedRegister() + { + return App.PlcConfig.DisintegrationSpeed != 0 ? App.PlcConfig.DisintegrationSpeed : (ushort)330; + } + private static async Task WriteDisintegrationTimeAsync(double value) { ushort registerAddress = ResolveDisintegrationTimeRegister(); @@ -341,6 +353,15 @@ namespace TabletTester2025 ushort.MaxValue)); } + private static async Task WriteDisintegrationSpeedAsync(double value) + { + ushort registerAddress = ResolveDisintegrationSpeedRegister(); + if (registerAddress == 0) + throw new InvalidOperationException("崩解升降频次PLC寄存器地址未配置。"); + + await App.PlcService.WriteFloatAsync(registerAddress, (float)value); + } + private static async Task WriteDissolution1SpeedAsync(double value) { ushort registerAddress = ResolveDissolution1SpeedRegister(); diff --git a/appsettings.json b/appsettings.json index 0e44638..b80f9a2 100644 --- a/appsettings.json +++ b/appsettings.json @@ -29,6 +29,7 @@ "FriabilityRpm": 320, // 脆碎度转速 r/min "FriabilityRounds": 410, // 脆碎圈数 "FriabilityRoundsBox": 410, // 兼容旧字段:脆碎圈数 + "FriabilityRealtimeRounds": 82, // 脆碎实时圈数 "DisintegrationSeconds": 420, //崩解时间