diff --git a/60.面罩视野测试仪(王蓝峰)/HMI/面罩视野测试仪1.exob b/60.面罩视野测试仪(王蓝峰)/HMI/面罩视野测试仪1.exob index 246e642..9fb7598 100644 Binary files a/60.面罩视野测试仪(王蓝峰)/HMI/面罩视野测试仪1.exob and b/60.面罩视野测试仪(王蓝峰)/HMI/面罩视野测试仪1.exob differ diff --git a/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪 - 副本.gxw b/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪 - 副本.gxw deleted file mode 100644 index 4dd8dfa..0000000 Binary files a/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪 - 副本.gxw and /dev/null differ diff --git a/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪_出版.gxw b/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪_出版.gxw deleted file mode 100644 index 81ca36f..0000000 Binary files a/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪_出版.gxw and /dev/null differ diff --git a/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪——120°版本.gxw b/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪——120°版本.gxw deleted file mode 100644 index e52c02b..0000000 Binary files a/60.面罩视野测试仪(王蓝峰)/PLC/面罩视野测试仪——120°版本.gxw and /dev/null differ diff --git a/App.xaml b/App.xaml index 4274050..97e1eea 100644 --- a/App.xaml +++ b/App.xaml @@ -1,7 +1,7 @@  + StartupUri="Views/TestView.xaml"> diff --git a/Helpers/PlcConfiguration.cs b/Helpers/PlcConfiguration.cs index 559ce73..b5cb241 100644 --- a/Helpers/PlcConfiguration.cs +++ b/Helpers/PlcConfiguration.cs @@ -17,39 +17,50 @@ public ushort PressureRegisterStation1 { get; set; } public ushort PressureRegisterStation2 { get; set; } public ushort PressureRegisterStation3 { get; set; } - public ushort PressureModeRegister { get; set; } - public ushort PressCoil { get; set; } - public ushort StartCoil { get; set; } - public ushort EnableCoil { get; set; } - public ushort StopCoil { get; set; } - public ushort PressureUpperLimit { get; set; } = 300; - public ushort PressureRate { get; set; } = 280; - public ushort PressureCoeff { get; set; } = 282; - public ushort HPCoeff1 { get; set; } = 3120; - public ushort LPCoeff1 { get; set; } = 3122; - public ushort HPCoeff2 { get; set; } = 3124; - public ushort LPCoeff2 { get; set; } = 3126; - public ushort HPCoeff3 { get; set; } = 3128; - public ushort LPCoeff3 { get; set; } = 3130; - public ushort LargeFlowCoeff1 { get; set; } = 3048; - public ushort SmallFlowCoeff1 { get; set; } = 380; - public ushort LargeFlowCoeff2 { get; set; } = 1218; - public ushort SmallFlowCoeff2 { get; set; } = 1318; - public ushort LargeFlowCoeff3 { get; set; } = 1418; - public ushort SmallFlowCoeff3 { get; set; } = 1468; - public ushort FlowModeRegister1 { get; set; } = 5; // 工位1流量模式 (0=大,1=小) - public ushort FlowModeRegister2 { get; set; } = 6; - public ushort FlowModeRegister3 { get; set; } = 7; - // 校准系数地址(需与PLC约定) - public ushort PressureCalibZero { get; set; } = 3200; - public ushort PressureCalibSpan { get; set; } = 3202; - public ushort FlowCalibZero { get; set; } = 3204; - public ushort FlowCalibSpan { get; set; } = 3206; + + + // 设备参数地址(示例,请根据实际PLC地址修改) + public ushort UpperLampData1 { get; set; } = 350; + public ushort UpperLampData2 { get; set; } = 351; + public ushort UpperLampData3 { get; set; } = 352; + public ushort UpperLampData4 { get; set; } = 353; + public ushort UpperLampData5 { get; set; } = 354; + public ushort UpperLampData6 { get; set; } = 355; + + public ushort LowerLampData1 { get; set; } = 356; + public ushort LowerLampData2 { get; set; } = 357; + public ushort LowerLampData3 { get; set; } = 358; + public ushort LowerLampData4 { get; set; } = 359; + public ushort LowerLampData5 { get; set; } = 360; + public ushort LowerLampData6 { get; set; } = 361; + + public ushort LeftEyeAreaCoeff { get; set; } = 212; + public ushort RightEyeAreaCoeff { get; set; } = 214; + public ushort SaveRateCorrectionCoeff { get; set; } = 428; + + public ushort MiddleLamp1 { get; set; } = 362; + public ushort MiddleLamp2 { get; set; } = 363; + public ushort MiddleLamp3 { get; set; } = 364; + public ushort MiddleLamp4 { get; set; } = 365; + public ushort MiddleLamp5 { get; set; } = 366; + public ushort MiddleLamp6 { get; set; } = 367; + public ushort MiddleLamp7 { get; set; } = 368; + + public ushort MotorLimit { get; set; } = 330; + public ushort ResetCompensation { get; set; } = 340; // 新增复位补偿 + + + + + + + + @@ -58,7 +69,11 @@ } - + public enum ParameterDataType + { + Int16, // 16位整数 + Float32 // 32位浮点数 + } public interface IPlcService @@ -75,6 +90,10 @@ Task ReadHoldingRegistersAsync(ushort startAddress, ushort count); Task WriteSingleRegisterAsync(ushort registerAddress, ushort value); + + float UshortToFloat(ushort P1, ushort P2); + + Task WriteMultipleRegistersAsync(ushort registerAddress, float value); } } \ No newline at end of file diff --git a/Service/ModbusTcpPlcService.cs b/Service/ModbusTcpPlcService.cs index d304d17..0fb2263 100644 --- a/Service/ModbusTcpPlcService.cs +++ b/Service/ModbusTcpPlcService.cs @@ -104,6 +104,51 @@ namespace MembranePoreTester.Communication return await ReadFloatAsync(startAddress); } + /// + /// ushort转为float类型 + /// + /// + /// + /// float型数据 + public float UshortToFloat(ushort P1, ushort P2) + { + int intSign, intSignRest, intExponent, intExponentRest; + float faResult, faDigit; + intSign = P1 / 32768; + intSignRest = P1 % 32768; + intExponent = intSignRest / 128; + intExponentRest = intSignRest % 128; + faDigit = (float)(intExponentRest * 65536 + P2) / 8388608; + faResult = (float)Math.Pow(-1, intSign) * (float)Math.Pow(2, intExponent - 127) * (faDigit + 1); + return faResult; + } + + public async Task WriteMultipleRegistersAsync(ushort registerAddress, float value) + { + await EnsureConnectedAsync(); + await Task.Delay(100); + await _master.WriteMultipleRegistersAsync(_config.SlaveId, registerAddress, SplitFloatToUShortArray((float)value)); + } + + + /// + /// Float转为Ushort数组发送 + /// + /// + /// 返回ushort数组 + public ushort[] SplitFloatToUShortArray(float value) + { + byte[] floatBytes = BitConverter.GetBytes(value); + ushort[] ushortArray = new ushort[floatBytes.Length / 2]; + + for (int i = 0, j = 0; i < floatBytes.Length; i += 2, j++) + { + ushortArray[j] = BitConverter.ToUInt16(floatBytes, i); + } + + return ushortArray; + } + public void Dispose() { diff --git a/ViewModels/TestViewModel.cs b/ViewModels/TestViewModel.cs new file mode 100644 index 0000000..340b97b --- /dev/null +++ b/ViewModels/TestViewModel.cs @@ -0,0 +1,263 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using System; +using System.Windows.Forms; +using System.Windows.Threading; + +namespace MembranePoreTester +{ + public partial class TestViewModel : ObservableObject + { + private readonly DispatcherTimer _angleUpdateTimer; + private bool _isTestRunning; + + public TestViewModel() + { + _angleUpdateTimer = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(100) + }; + _angleUpdateTimer.Tick += AngleUpdateTimer_Tick; + + // 默认值 + ResolutionAngle = 0.1; + RotationSpeed = 30; + LeftEyeCoeff = 1.0; + RightEyeCoeff = 1.0; + RetentionCorrectionCoeff = 1.0; + IsSampleMode = true; + } + + // 当前模式显示文本 + [ObservableProperty] + private string _currentMode = "试样测试"; + + // 模式切换 + private bool _isBlankMode; + public bool IsBlankMode + { + get => _isBlankMode; + set + { + if (SetProperty(ref _isBlankMode, value) && value) + { + CurrentMode = "空白模式"; + IsSampleMode = false; + OnModeChanged(); + } + } + } + + private bool _isSampleMode; + public bool IsSampleMode + { + get => _isSampleMode; + set + { + if (SetProperty(ref _isSampleMode, value) && value) + { + CurrentMode = "试样测试"; + IsBlankMode = false; + OnModeChanged(); + } + } + } + + // 参数设置 + [ObservableProperty] + private double _resolutionAngle; + + [ObservableProperty] + private double _rotationSpeed; + + [ObservableProperty] + private double _currentAngle; + + // 视野面积数据 + [ObservableProperty] + private double _leftEyeArea; + + [ObservableProperty] + private double _rightEyeArea; + + [ObservableProperty] + private double _binocularArea; + + [ObservableProperty] + private double _lowerField; + + [ObservableProperty] + private double _blankArea; + + [ObservableProperty] + private double _fieldRetentionRate; + + // 灯条数据 + [ObservableProperty] + private double _upperLampData; + + [ObservableProperty] + private double _middleLampData; + + [ObservableProperty] + private double _lowerLampData; + + // 面积系数 + [ObservableProperty] + private double _leftEyeCoeff; + + [ObservableProperty] + private double _rightEyeCoeff; + + [ObservableProperty] + private double _retentionCorrectionCoeff; + + // 命令 + [RelayCommand] + private void Reset() + { + CurrentAngle = 0; + // 用户在此添加硬件复位代码 + } + + [RelayCommand] + private void OpenLeftEye() + { + // 用户实现左眼开逻辑 + UpdateLeftEyeArea(); + } + + [RelayCommand] + private void OpenRightEye() + { + // 用户实现右眼开逻辑 + UpdateRightEyeArea(); + } + + [RelayCommand] + private void Reverse() + { + // 反转方向 + RotationSpeed = -Math.Abs(RotationSpeed); + } + + [RelayCommand] + private void Forward() + { + // 正转方向 + RotationSpeed = Math.Abs(RotationSpeed); + } + + [RelayCommand] + private void StartTest() + { + if (_isTestRunning) return; + _isTestRunning = true; + _angleUpdateTimer.Start(); + } + + [RelayCommand] + private void StopTest() + { + _isTestRunning = false; + _angleUpdateTimer.Stop(); + } + + // 导航命令(供用户跳转页面) + [RelayCommand] + private void NavigateHome() + { + // 用户实现:关闭当前窗口或切换主窗口内容 + } + + [RelayCommand] + private void NavigateTest() + { + // 已在测试界面,可忽略 + } + + [RelayCommand] + private void NavigateData() + { + // 跳转到数据记录界面 + } + + [RelayCommand] + private void NavigateRecord() + { + // 跳转到记录画面 + } + + // 内部辅助方法 + private void OnModeChanged() + { + if (IsBlankMode) + { + BlankArea = 0; + FieldRetentionRate = 0; + } + else + { + CalculateFieldAreas(); + } + } + + private void AngleUpdateTimer_Tick(object sender, EventArgs e) + { + if (!_isTestRunning) return; + + // 模拟角度变化 + CurrentAngle += RotationSpeed * 0.1; + if (CurrentAngle >= 360) CurrentAngle -= 360; + if (CurrentAngle < 0) CurrentAngle += 360; + + CalculateFieldAreas(); + UpdateLampData(); + } + + private void CalculateFieldAreas() + { + double angle = CurrentAngle; + LeftEyeArea = Math.Round(50 + 30 * Math.Sin(angle * Math.PI / 180) * LeftEyeCoeff, 3); + RightEyeArea = Math.Round(50 + 30 * Math.Cos(angle * Math.PI / 180) * RightEyeCoeff, 3); + BinocularArea = Math.Round(LeftEyeArea + RightEyeArea - 20, 3); + LowerField = Math.Round(30 + 20 * Math.Sin(angle * Math.PI / 180), 1); + + if (IsBlankMode) + { + BlankArea = Math.Round(10 + 5 * Math.Sin(angle * Math.PI / 180), 3); + FieldRetentionRate = BinocularArea > 0 + ? Math.Round((BinocularArea - BlankArea) / BinocularArea * 100, 2) + : 0; + } + else + { + FieldRetentionRate = Math.Round(BinocularArea / 100 * 100 * RetentionCorrectionCoeff, 2); + if (FieldRetentionRate > 100) FieldRetentionRate = 100; + if (FieldRetentionRate < 0) FieldRetentionRate = 0; + } + } + + private void UpdateLeftEyeArea() + { + LeftEyeArea = Math.Round(LeftEyeArea + 5, 3); + if (LeftEyeArea > 100) LeftEyeArea = 100; + CalculateFieldAreas(); + } + + private void UpdateRightEyeArea() + { + RightEyeArea = Math.Round(RightEyeArea + 5, 3); + if (RightEyeArea > 100) RightEyeArea = 100; + CalculateFieldAreas(); + } + + private void UpdateLampData() + { + Random rand = new Random(); + UpperLampData = Math.Round(rand.NextDouble() * 100, 2); + MiddleLampData = Math.Round(rand.NextDouble() * 100, 2); + LowerLampData = Math.Round(rand.NextDouble() * 100, 2); + } + } +} \ No newline at end of file diff --git a/Views/MainWindow.xaml b/Views/MainWindow.xaml index 981a674..50c2d89 100644 --- a/Views/MainWindow.xaml +++ b/Views/MainWindow.xaml @@ -2,11 +2,87 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MembranePoreTester" - Title="设备控制系统" - Width="1024" Height="768" + Title="智能设备控制平台" + Width="1024" MinHeight="768" WindowState="Maximized" WindowStartupLocation="CenterScreen" - ResizeMode="NoResize" - Background="{StaticResource WindowBackground}"> + ResizeMode="CanResize" + Background="#F5F7FA" FontFamily="Segoe UI"> + + + + + + + + + + + + + + + @@ -14,25 +90,31 @@ - - + + + + + + + - + - + - + + + @@ -44,46 +126,46 @@ + - - + + @@ -96,53 +178,53 @@ - + + + - - - + @@ -150,40 +232,49 @@ - - + + -