This commit is contained in:
GukSang.Jin
2026-05-20 14:51:00 +08:00
parent 263fffbcf5
commit 0cba5198f2
7 changed files with 66 additions and 5 deletions

View File

@@ -31,6 +31,7 @@
public ushort FriabilityRpm { get; set; } public ushort FriabilityRpm { get; set; }
public ushort FriabilityRounds { get; set; } public ushort FriabilityRounds { get; set; }
public ushort FriabilityRoundsBox { get; set; } // 兼容旧配置字段 public ushort FriabilityRoundsBox { get; set; } // 兼容旧配置字段
public ushort FriabilityRealtimeRounds { get; set; }
public ushort FriabilityTestTime { get; set; } public ushort FriabilityTestTime { get; set; }
public ushort FriabilityWeightBefore { get; set; } public ushort FriabilityWeightBefore { get; set; }
public ushort FriabilityWeightAfter { get; set; } public ushort FriabilityWeightAfter { get; set; }

View File

@@ -24,6 +24,7 @@ namespace TabletTester2025.Services
414 => 4.9f + (float)_rand.NextDouble() * 2, // 后重 414 => 4.9f + (float)_rand.NextDouble() * 2, // 后重
416 => 1.0f, // 失重率% 416 => 1.0f, // 失重率%
300 => 100.0f, // 硬度加压速度(mm/min) 300 => 100.0f, // 硬度加压速度(mm/min)
330 => 31.0f, // 崩解升降频次(次/min)
340 => 50f, // 溶出速度1(r/min) 340 => 50f, // 溶出速度1(r/min)
350 => 50f, // 溶出速度2(r/min) 350 => 50f, // 溶出速度2(r/min)
400 => 50 + (float)_rand.NextDouble() * 30, // 转速 400 => 50 + (float)_rand.NextDouble() * 30, // 转速
@@ -40,6 +41,7 @@ namespace TabletTester2025.Services
{ {
int value = startAddress switch int value = startAddress switch
{ {
82 => _rand.Next(0, 101), // 脆碎实时圈数
410 => 100, // 脆碎圈数 410 => 100, // 脆碎圈数
430 => 30, // 溶出1时间(min) 430 => 30, // 溶出1时间(min)
440 => 30, // 溶出2时间(min) 440 => 30, // 溶出2时间(min)

View File

@@ -149,6 +149,7 @@ namespace TabletTester2025.ViewModels
[ObservableProperty] private bool _friabilityClockwise = true; [ObservableProperty] private bool _friabilityClockwise = true;
[ObservableProperty] private bool _friabilityCounterClockwise; [ObservableProperty] private bool _friabilityCounterClockwise;
[ObservableProperty] private double _friabilityCurrentRpm; [ObservableProperty] private double _friabilityCurrentRpm;
[ObservableProperty] private int _friabilityRealtimeRounds;
[ObservableProperty] private int _friabilityRemainingRounds = 100; [ObservableProperty] private int _friabilityRemainingRounds = 100;
public IAsyncRelayCommand StopHardnessCommand { get; } public IAsyncRelayCommand StopHardnessCommand { get; }
public IAsyncRelayCommand StopFriabilityCommand { get; } public IAsyncRelayCommand StopFriabilityCommand { get; }
@@ -1888,6 +1889,7 @@ namespace TabletTester2025.ViewModels
int totalRounds = Math.Max(1, FriabilityTargetRounds); int totalRounds = Math.Max(1, FriabilityTargetRounds);
FriabilityRemainingRounds = totalRounds; FriabilityRemainingRounds = totalRounds;
FriabilityCurrentRpm = rpm; FriabilityCurrentRpm = rpm;
await RefreshFriabilityRealtimeRoundsAsync();
await PulseCoilAsync(startCoil); await PulseCoilAsync(startCoil);
int durationMs = (int)Math.Ceiling(testTimeMin * 60 * 1000); // 总运行时间(毫秒) int durationMs = (int)Math.Ceiling(testTimeMin * 60 * 1000); // 总运行时间(毫秒)
@@ -1904,6 +1906,8 @@ namespace TabletTester2025.ViewModels
// 更新界面绑定的剩余圈数 // 更新界面绑定的剩余圈数
FriabilityRemainingRounds = remainingRounds; FriabilityRemainingRounds = remainingRounds;
if (i % 500 == 0)
await RefreshFriabilityRealtimeRoundsAsync();
// 等待100ms再更新下一次 // 等待100ms再更新下一次
await Task.Delay(100); await Task.Delay(100);
@@ -1914,6 +1918,7 @@ namespace TabletTester2025.ViewModels
double weightAfter = await ReadFriabilityWeightAsync(ResolveFriabilityWeightAfterRegister(), "脆碎后重量"); double weightAfter = await ReadFriabilityWeightAsync(ResolveFriabilityWeightAfterRegister(), "脆碎后重量");
SetFriabilityWeightFromPlc(weightAfter: weightAfter); SetFriabilityWeightFromPlc(weightAfter: weightAfter);
FriabilityCurrentRpm = rpm; FriabilityCurrentRpm = rpm;
await RefreshFriabilityRealtimeRoundsAsync();
bool localLossReady = TryCalculateFriabilityLossFromWeights(out double localLossPercent); bool localLossReady = TryCalculateFriabilityLossFromWeights(out double localLossPercent);
if (localLossReady) if (localLossReady)
@@ -1962,6 +1967,31 @@ namespace TabletTester2025.ViewModels
return value; 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() private async Task RunDisintegrationAsync()
{ {
if (_isDisintegrationRunning) return; if (_isDisintegrationRunning) return;

View File

@@ -474,10 +474,6 @@
<GroupBox Header="当前参数" Grid.Row="0"> <GroupBox Header="当前参数" Grid.Row="0">
<WrapPanel> <WrapPanel>
<StackPanel Style="{StaticResource ParamRow}">
<TextBlock Text="试验时间(min)" Style="{StaticResource ParamLabel}"/>
<TextBlock Text="{Binding FriabilityTargetTimeMin, StringFormat=F1}" FontSize="18" FontWeight="SemiBold" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Style="{StaticResource ParamRow}"> <StackPanel Style="{StaticResource ParamRow}">
<TextBlock Text="转速设置(r/min)" Style="{StaticResource ParamLabel}"/> <TextBlock Text="转速设置(r/min)" Style="{StaticResource ParamLabel}"/>
<TextBlock Text="{Binding FriabilityTargetRpm, StringFormat=F1}" FontSize="18" FontWeight="SemiBold" VerticalAlignment="Center"/> <TextBlock Text="{Binding FriabilityTargetRpm, StringFormat=F1}" FontSize="18" FontWeight="SemiBold" VerticalAlignment="Center"/>
@@ -494,7 +490,13 @@
</GroupBox> </GroupBox>
<GroupBox Header="测试结果" Grid.Row="1"> <GroupBox Header="测试结果" Grid.Row="1">
<UniformGrid Columns="3"> <UniformGrid Columns="4">
<Border Style="{StaticResource MetricCard}">
<StackPanel>
<TextBlock Text="实时圈数" Style="{StaticResource MetricLabel}"/>
<TextBlock Text="{Binding FriabilityRealtimeRounds}" Foreground="#1565C0" Style="{StaticResource MetricValue}"/>
</StackPanel>
</Border>
<Border Style="{StaticResource MetricCard}"> <Border Style="{StaticResource MetricCard}">
<StackPanel> <StackPanel>
<TextBlock Text="脆碎前质量(g)" Style="{StaticResource MetricLabel}"/> <TextBlock Text="脆碎前质量(g)" Style="{StaticResource MetricLabel}"/>

View File

@@ -130,6 +130,10 @@
<TextBlock Text="崩解时间(min):" Style="{StaticResource ParamLabel}"/> <TextBlock Text="崩解时间(min):" Style="{StaticResource ParamLabel}"/>
<TextBox x:Name="DisintegrationTimeMinBox"/> <TextBox x:Name="DisintegrationTimeMinBox"/>
</StackPanel> </StackPanel>
<StackPanel Style="{StaticResource ParamRow}">
<TextBlock Text="升降频次(次/min):" Style="{StaticResource ParamLabel}"/>
<TextBox x:Name="DisintegrationSpeedBox"/>
</StackPanel>
</WrapPanel> </WrapPanel>
<TextBlock Text="崩解时间按具体品种正文或企业批准标准设置,保存后立即写入设备。" <TextBlock Text="崩解时间按具体品种正文或企业批准标准设置,保存后立即写入设备。"
Style="{StaticResource StandardNote}"/> Style="{StaticResource StandardNote}"/>

View File

@@ -26,6 +26,9 @@ namespace TabletTester2025
await LoadPlcFloatToTextBoxAsync(ResolveFriabilityRpmRegister(), FriabilityRpmBox); await LoadPlcFloatToTextBoxAsync(ResolveFriabilityRpmRegister(), FriabilityRpmBox);
await LoadPlcIntToTextBoxAsync(ResolveFriabilityRoundsRegister(), FriabilityRoundsBox); await LoadPlcIntToTextBoxAsync(ResolveFriabilityRoundsRegister(), FriabilityRoundsBox);
// 崩解
await LoadPlcFloatToTextBoxAsync(ResolveDisintegrationSpeedRegister(), DisintegrationSpeedBox);
// 溶出度 // 溶出度
await LoadPlcFloatToTextBoxAsync(ResolveDissolution1SpeedRegister(), Dissolution1SpeedBox); await LoadPlcFloatToTextBoxAsync(ResolveDissolution1SpeedRegister(), Dissolution1SpeedBox);
await LoadPlcFloatToTextBoxAsync(ResolveDissolution2SpeedRegister(), Dissolution2SpeedBox); await LoadPlcFloatToTextBoxAsync(ResolveDissolution2SpeedRegister(), Dissolution2SpeedBox);
@@ -44,6 +47,7 @@ namespace TabletTester2025
FriabilityRoundsBox.Text = ResolveFriabilityTargetRounds(p).ToString(); FriabilityRoundsBox.Text = ResolveFriabilityTargetRounds(p).ToString();
FriabilityMaxLossBox.Text = p.FriabilityMaxLossPercent.ToString(); FriabilityMaxLossBox.Text = p.FriabilityMaxLossPercent.ToString();
DisintegrationTimeMinBox.Text = ResolveDisintegrationTimeMin(p).ToString("0.###"); DisintegrationTimeMinBox.Text = ResolveDisintegrationTimeMin(p).ToString("0.###");
DisintegrationSpeedBox.Text = p.DisintegrationSpeedRpm.ToString("0.###");
//DisintegrationTempBox.Text = p.DisintegrationTemperatureC.ToString(); //DisintegrationTempBox.Text = p.DisintegrationTemperatureC.ToString();
//DissolutionTempBox.Text = p.DissolutionTemperatureC.ToString(); //DissolutionTempBox.Text = p.DissolutionTemperatureC.ToString();
Dissolution1TimeBox.Text = p.Dissolution1TimeMin.ToString(); Dissolution1TimeBox.Text = p.Dissolution1TimeMin.ToString();
@@ -82,6 +86,8 @@ namespace TabletTester2025
p.FriabilityTargetRounds = ParsePositiveInt(FriabilityRoundsBox.Text, "脆碎圈数"); p.FriabilityTargetRounds = ParsePositiveInt(FriabilityRoundsBox.Text, "脆碎圈数");
p.FriabilityMaxLossPercent = ParseFiniteDouble(FriabilityMaxLossBox.Text, "最大失重率"); p.FriabilityMaxLossPercent = ParseFiniteDouble(FriabilityMaxLossBox.Text, "最大失重率");
double disintegrationTimeMin = ParsePositiveDouble(DisintegrationTimeMinBox.Text, "崩解时间"); double disintegrationTimeMin = ParsePositiveDouble(DisintegrationTimeMinBox.Text, "崩解时间");
double disintegrationSpeed = ParsePositiveDouble(DisintegrationSpeedBox.Text, "升降频次");
p.DisintegrationSpeedRpm = disintegrationSpeed;
p.DisintegrationMaxSeconds = ToDisintegrationSeconds(disintegrationTimeMin); p.DisintegrationMaxSeconds = ToDisintegrationSeconds(disintegrationTimeMin);
//p.DisintegrationTemperatureC = ParseFiniteDouble(DisintegrationTempBox.Text, "崩解介质温度"); //p.DisintegrationTemperatureC = ParseFiniteDouble(DisintegrationTempBox.Text, "崩解介质温度");
//p.DissolutionTemperatureC = ParseFiniteDouble(DissolutionTempBox.Text, "溶出介质温度"); //p.DissolutionTemperatureC = ParseFiniteDouble(DissolutionTempBox.Text, "溶出介质温度");
@@ -98,6 +104,7 @@ namespace TabletTester2025
await WriteHardnessDamageThresholdAsync(hardnessDamageThreshold); await WriteHardnessDamageThresholdAsync(hardnessDamageThreshold);
await WriteFriabilityRpmAsync(friabilityRpm); await WriteFriabilityRpmAsync(friabilityRpm);
await WriteDisintegrationTimeAsync(disintegrationTimeMin); await WriteDisintegrationTimeAsync(disintegrationTimeMin);
await WriteDisintegrationSpeedAsync(disintegrationSpeed);
await WriteDissolution1SpeedAsync(dissolution1Speed); await WriteDissolution1SpeedAsync(dissolution1Speed);
await WriteDissolution2SpeedAsync(dissolution2Speed); await WriteDissolution2SpeedAsync(dissolution2Speed);
await WriteDissolution1TimeAsync(p.Dissolution1TimeMin); await WriteDissolution1TimeAsync(p.Dissolution1TimeMin);
@@ -329,6 +336,11 @@ namespace TabletTester2025
return App.PlcConfig.DisintegrationTime != 0 ? App.PlcConfig.DisintegrationTime : (ushort)420; 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) private static async Task WriteDisintegrationTimeAsync(double value)
{ {
ushort registerAddress = ResolveDisintegrationTimeRegister(); ushort registerAddress = ResolveDisintegrationTimeRegister();
@@ -341,6 +353,15 @@ namespace TabletTester2025
ushort.MaxValue)); 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) private static async Task WriteDissolution1SpeedAsync(double value)
{ {
ushort registerAddress = ResolveDissolution1SpeedRegister(); ushort registerAddress = ResolveDissolution1SpeedRegister();

View File

@@ -29,6 +29,7 @@
"FriabilityRpm": 320, // 脆碎度转速 r/min "FriabilityRpm": 320, // 脆碎度转速 r/min
"FriabilityRounds": 410, // 脆碎圈数 "FriabilityRounds": 410, // 脆碎圈数
"FriabilityRoundsBox": 410, // 兼容旧字段:脆碎圈数 "FriabilityRoundsBox": 410, // 兼容旧字段:脆碎圈数
"FriabilityRealtimeRounds": 82, // 脆碎实时圈数
"DisintegrationSeconds": 420, //崩解时间 "DisintegrationSeconds": 420, //崩解时间