diff --git a/App.config b/App.config
new file mode 100644
index 0000000..91efc2e
--- /dev/null
+++ b/App.config
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/App.xaml b/App.xaml
new file mode 100644
index 0000000..c9219e0
--- /dev/null
+++ b/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/App.xaml.cs b/App.xaml.cs
new file mode 100644
index 0000000..7827d99
--- /dev/null
+++ b/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace 医用刨削器特征新版8
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/CurveWindow.xaml b/CurveWindow.xaml
new file mode 100644
index 0000000..1466c4d
--- /dev/null
+++ b/CurveWindow.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CurveWindow.xaml.cs b/CurveWindow.xaml.cs
new file mode 100644
index 0000000..84876fe
--- /dev/null
+++ b/CurveWindow.xaml.cs
@@ -0,0 +1,122 @@
+using OxyPlot;
+using OxyPlot.Series;
+using System.Windows;
+using System.Windows.Threading;
+
+namespace EmptyLoadTest
+{
+ public partial class CurveWindow : Window
+ {
+ private PlotModel _plotModel;
+ private LineSeries _torqueSpeedSeries;
+ private DispatcherTimer _updateTimer;
+ private static CurveWindow _instance;
+
+ // 用于存储数据的队列(支持后台记录)
+ private readonly Queue _dataQueue = new Queue();
+ private readonly object _lockObject = new object();
+
+ // 最大缓存数据点数
+ private const int MAX_CACHE_POINTS = 1000;
+
+ public static CurveWindow Instance
+ {
+ get
+ {
+ if (_instance == null || !_instance.IsLoaded)
+ {
+ _instance = new CurveWindow();
+ }
+ return _instance;
+ }
+ }
+
+ public CurveWindow()
+ {
+ InitializeComponent();
+ InitializeChart();
+ InitializeUpdateTimer();
+ }
+
+ // 外部调用此方法来更新数据(即使窗口未打开也会缓存)
+ public void UpdateData(float torque, float speed)
+ {
+ lock (_lockObject)
+ {
+ // 添加到队列
+ _dataQueue.Enqueue(new DataPoint(torque, speed));
+
+ // 限制队列大小
+ if (_dataQueue.Count > MAX_CACHE_POINTS)
+ {
+ _dataQueue.Dequeue();
+ }
+ }
+
+ // 如果窗口已打开,立即更新显示
+ if (this.IsLoaded && IsVisible)
+ {
+ ProcessQueuedData();
+ }
+ }
+
+ private void ProcessQueuedData()
+ {
+ lock (_lockObject)
+ {
+ while (_dataQueue.Count > 0)
+ {
+ var point = _dataQueue.Dequeue();
+ _torqueSpeedSeries.Points.Add(point);
+
+ // 限制显示的数据点数
+ if (_torqueSpeedSeries.Points.Count > 500)
+ {
+ _torqueSpeedSeries.Points.RemoveAt(0);
+ }
+ }
+
+ _plotModel.InvalidatePlot(true);
+ UpdateStatusDisplay();
+ }
+ }
+
+ private void UpdateTimer_Tick(object sender, EventArgs e)
+ {
+ try
+ {
+ // 处理队列中的数据
+ ProcessQueuedData();
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"曲线更新失败: {ex.Message}");
+ }
+ }
+
+ // 新增:获取当前数据点数
+ public int GetDataCount()
+ {
+ lock (_lockObject)
+ {
+ return _dataQueue.Count + _torqueSpeedSeries.Points.Count;
+ }
+ }
+
+ // 清空数据
+ public void ClearData()
+ {
+ lock (_lockObject)
+ {
+ _dataQueue.Clear();
+ _torqueSpeedSeries.Points.Clear();
+ }
+
+ if (this.IsLoaded)
+ {
+ _plotModel.InvalidatePlot(true);
+ UpdateStatusDisplay();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Data/BoolSign.cs b/Data/BoolSign.cs
new file mode 100644
index 0000000..7cf01e3
--- /dev/null
+++ b/Data/BoolSign.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace 软胶囊弹性硬度测试仪.Data
+{
+
+ public class BoolSignal
+ {
+ private bool _previousValue;
+
+ public event Action OnRisingEdge;
+ // bool value = true;
+ public bool Value { get; set; }
+
+ public void CheckRisingEdge()
+ {
+ if (Value && !_previousValue)
+ {
+ OnRisingEdge?.Invoke();
+ }
+ _previousValue = Value;
+ }
+ }
+
+}
diff --git a/Data/DataChange.cs b/Data/DataChange.cs
new file mode 100644
index 0000000..0b912a1
--- /dev/null
+++ b/Data/DataChange.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace 软胶囊弹性硬度测试仪
+{
+ public class DataChange
+ {
+ ///
+ /// 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;
+ }
+ ///
+ /// ushort转为int类型
+ ///
+ ///
+ ///
+ /// 返回int型数据
+ public int UshortToInt1(ushort u1, ushort u2)
+ {
+ ushort[] maidong = new ushort[2] { u1, u2 };
+ byte[] bytes = new byte[maidong.Length * 2];
+ Buffer.BlockCopy(maidong, 0, bytes, 0, bytes.Length);
+ int result = BitConverter.ToInt32(bytes, 0);
+ // 将字节数组转换为32位无符号整数
+ return result;
+
+ }
+ ///
+ /// 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;
+ }
+ ///
+ /// Int转为ushort数组发送
+ ///
+ ///
+ /// 返回ushort数组
+ public ushort[] intToushorts(int res)
+ {
+ ushort ust1 = (ushort)(res >> 16);
+ ushort ust2 = (ushort)res;
+ return new ushort[] { ust2, ust1 };
+ }
+ }
+}
diff --git a/Data/ExperData.cs b/Data/ExperData.cs
new file mode 100644
index 0000000..9b185e8
--- /dev/null
+++ b/Data/ExperData.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace 软胶囊弹性硬度测试仪
+{
+ public class ExperData: INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ #region 实验属性
+ static string experName = "";
+ ///
+ /// 实验人员
+ ///
+ public string ExperName { get { return experName; } set { experName = value; } }
+
+ static string experDate = "";
+ ///
+ /// 实验日期
+ ///
+ public string ExperDate { get { return experDate; } set { experDate = value; } }
+
+ static string experNum = "";
+ ///
+ /// 实验编号
+ ///
+ public string ExperNum { get { return experNum; } set { experNum = value; } }
+
+ static string experType = " ";
+ ///
+ /// 实验种类
+ ///
+ public string ExperType { get { return experType; } set { experType = value; } }
+ static float experMaskType = 2.0f;
+ ///
+ /// 口罩类型
+ ///
+ public float ExperMaskType { get { return experMaskType; } set { experMaskType = value; } }
+ ///
+ /// 面罩类型
+ ///
+ static string maskType;
+ public string MaskType { get { return maskType; } set { maskType = value; } }
+ static float _yangPinXiShu = 1.0f;
+ ///
+ /// 样品系数
+ ///
+ public float YangPinXiShu { get { return _yangPinXiShu; } set { _yangPinXiShu = value; } }
+ static string _testStatus = "";
+
+
+ ///
+ /// 实验状态
+ ///
+ public string TestStatus { get { return _testStatus; } set { _testStatus = value; } }
+ static float benDiNongDu = 0.00f;
+ ///
+ /// 本底浓度
+ ///
+ public float BenDiNongDu { get { return benDiNongDu; } set { benDiNongDu = value; } }
+
+ static float huanJingWenDu = 0.00f;
+ ///
+ /// 环境温度
+ ///
+ public float HuanJingWenDu { get { return huanJingWenDu; } set { huanJingWenDu = value; } }
+
+
+ static float huanJingShiDu = 0.00f;
+ ///
+ /// 环境湿度
+ ///
+ public float HuanJingShiDu { get { return huanJingShiDu; } set { huanJingShiDu = value; } }
+
+ static float o2NongDu = 0.00f;
+ ///
+ /// 环境氧浓度
+ ///
+ public float O2NongDu { get { return o2NongDu; } set { o2NongDu = value; } }
+
+ static float cO2NongDu = 0.00f;
+ ///
+ /// 环境C02浓度
+ ///
+ public float CO2NongDu_Indoor { get { return cO2NongDu; } set { cO2NongDu = value; } }
+
+ static float inDoor_TSINongDu = 0.00f;
+ ///
+ /// 环境气溶胶浓度
+ ///
+ public float InDoor_TSINongDu { get { return inDoor_TSINongDu; } set { inDoor_TSINongDu = value; } }
+
+ static float mask_CO2NongDu = 0.00f;
+ ///
+ /// 口罩内CO2浓度
+ ///
+ public float Mask_CO2NongDu { get { return mask_CO2NongDu; } set { mask_CO2NongDu = value; } }
+
+ static float mask_TSINongDu = 0.00f;
+ ///
+ /// 口罩内气溶胶浓度
+ ///
+ public float Mask_TSINongDu { get { return mask_TSINongDu; } set { mask_TSINongDu = value; } }
+
+ static float _liuLiang = 0.00f;
+ ///
+ /// 流量
+ ///
+ public float LiuLiang { get { return _liuLiang; } set { _liuLiang = value; } }
+ static float _xieloulv = 0.00f;
+ ///
+ /// 泄露率
+ ///
+ public float XieLouLv { get { return _xieloulv; } set { _xieloulv = value; } }
+
+
+ #endregion
+
+ #region 泄露率计算
+ //单独动作泄露率
+ public float CumulativeLeakageRate(List inDoor_Tsi,List out_Door_Tsi,float benDiNongdu,float xiShu)
+ {
+ if (inDoor_Tsi.Count != 0 && out_Door_Tsi.Count != 0&& benDiNongdu!=0.0f)
+ {
+ //计算室内Tsi浓度平均值
+ float inDoor_Tsi_Avg = inDoor_Tsi.Average();
+ //计算室外Tsi浓度平均值
+ float out_Door_Tsi_Avg = out_Door_Tsi.Average();
+ //计算泄露率
+ float leakageRate = ((out_Door_Tsi_Avg - inDoor_Tsi_Avg) * xiShu) / benDiNongdu;
+ return leakageRate;
+ }
+ else
+ {
+ return 0.00f;
+ }
+
+ }
+ //全部动作泄露率
+ public float CumulativeLeakageRate_All(List All_Cv_List)
+
+ {
+ return All_Cv_List.Average();
+ }
+ #endregion
+
+ }
+}
diff --git a/Data/Function.cs b/Data/Function.cs
new file mode 100644
index 0000000..72ac304
--- /dev/null
+++ b/Data/Function.cs
@@ -0,0 +1,222 @@
+using Modbus.Device;
+using Modbus;
+using Sunny.UI;
+using System;
+using System.Threading;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace 软胶囊弹性硬度测试仪
+{
+ public class Function
+ {
+ ModbusMaster master;
+ IModbusMaster modbusMaster;
+ DataChange dc = new DataChange();
+ public enum ButtonType
+ {
+ 复归型,
+ 切换型,
+ 置位型,
+ 复位型
+ }
+ public enum DataType
+ {
+ 整形,
+ 浮点型
+ }
+ public Function(ModbusMaster master_in)
+ {
+ this.master = master_in;
+ }
+
+ public Function(IModbusMaster modbusMaster)
+ {
+ this.modbusMaster = modbusMaster;
+ }
+
+ public void BtnClickFunction(ButtonType buttonType, ushort address)
+ {
+ try
+ {
+ switch (buttonType)
+ {
+ case ButtonType.复归型:
+ master.WriteSingleCoil(1, address, true);
+ Thread.Sleep(100);
+ master.WriteSingleCoil(1, address, false);
+ Thread.Sleep(100);
+ break;
+ case ButtonType.切换型:
+ if (master.ReadCoils(1, address, 1)[0])
+ {
+ master.WriteSingleCoil(1, address, false); Thread.Sleep(100);
+ }
+ else
+ { master.WriteSingleCoil(1, address, true); Thread.Sleep(100); }
+ break;
+ case ButtonType.置位型:
+ master.WriteSingleCoil(1, address, true);
+ Thread.Sleep(100);
+ break;
+ case ButtonType.复位型:
+ master.WriteSingleCoil(1, address, false);
+ Thread.Sleep(100);
+ break;
+ default:
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+
+ }
+
+ }
+
+ public void BtnClickFunctionForNew(ButtonType buttonType, ushort address)
+ {
+ try
+ {
+ switch (buttonType)
+ {
+ case ButtonType.复归型:
+ modbusMaster.WriteSingleCoil(1, address, true);
+ Thread.Sleep(100);
+ modbusMaster.WriteSingleCoil(1, address, false);
+ Thread.Sleep(100);
+ break;
+ case ButtonType.切换型:
+ if (modbusMaster.ReadCoils(1, address, 1)[0])
+ {
+ modbusMaster.WriteSingleCoil(1, address, false); Thread.Sleep(100);
+ }
+ else
+ { modbusMaster.WriteSingleCoil(1, address, true); Thread.Sleep(100); }
+ break;
+ case ButtonType.置位型:
+ modbusMaster.WriteSingleCoil(1, address, true);
+ Thread.Sleep(100);
+ break;
+ case ButtonType.复位型:
+ modbusMaster.WriteSingleCoil(1, address, false);
+ Thread.Sleep(100);
+ break;
+ default:
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+
+ }
+
+ }
+ public void WriteToPLC(string inPutValue, ushort address, DataType dataType)
+ {
+
+ try
+ {
+ switch (dataType)
+ {
+ case DataType.浮点型:
+ double value = inPutValue.ToDouble();
+ if (UIInputDialog.ShowInputDoubleDialog(ref value, UIStyle.Inherited, desc: "请输入值", showMask: false))
+ {
+
+ master.WriteMultipleRegisters(1, address, dc.SplitFloatToUShortArray((float)value));
+ }
+ break;
+ case DataType.整形:
+ int value_int = inPutValue.ToInt();
+ if (UIInputDialog.ShowInputIntegerDialog(ref value_int, UIStyle.Inherited, desc: "请输入数据:"))
+ {
+
+ master.WriteMultipleRegisters(1, address, dc.intToushorts(value_int));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("操作失败!" + "\n" + "\n" + ex.Message, "错误");
+ }
+
+ }
+
+ public void WriteToPLCForNew(string inPutValue, ushort address, DataType dataType)
+ {
+ try
+ {
+ //KeyboardHelper.ShowSoftKeyboard();
+ switch (dataType)
+ {
+ case DataType.浮点型:
+ double value = inPutValue.ToDouble();
+
+ if (UIInputDialog.ShowInputDoubleDialog(ref value, UIStyle.Inherited,3, desc: "请输入值", showMask: false))
+ {
+
+ modbusMaster.WriteMultipleRegisters(1, address, dc.SplitFloatToUShortArray((float)value));
+ }
+ break;
+ case DataType.整形:
+ int value_int = inPutValue.ToInt();
+ if (UIInputDialog.ShowInputIntegerDialog(ref value_int, UIStyle.Inherited, desc: "请输入数据:"))
+ {
+ modbusMaster.WriteMultipleRegisters(1, address, dc.intToushorts(value_int));
+ }
+ break;
+ default:
+ break;
+ }
+
+ //KeyboardHelper.HideSoftKeyboard();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("操作失败!" + "\n" + "\n" + ex.Message, "错误");
+ }
+
+ }
+
+
+ public void WriteToPLCForNewForThree(string inPutValue, ushort address, DataType dataType)
+ {
+ try
+ {
+ //KeyboardHelper.ShowSoftKeyboard();
+ switch (dataType)
+ {
+ case DataType.浮点型:
+ double value = inPutValue.ToDouble();
+
+ if (UIInputDialog.ShowInputDoubleDialog(ref value, UIStyle.Inherited, 3, desc: "请输入值", showMask: false))
+ {
+
+ modbusMaster.WriteMultipleRegisters(1, address, dc.SplitFloatToUShortArray((float)value));
+ }
+ break;
+ case DataType.整形:
+ int value_int = inPutValue.ToInt();
+ if (UIInputDialog.ShowInputIntegerDialog(ref value_int, UIStyle.Inherited, desc: "请输入数据:"))
+ {
+ modbusMaster.WriteMultipleRegisters(1, address, dc.intToushorts(value_int));
+ }
+ break;
+ default:
+ break;
+ }
+
+ //KeyboardHelper.HideSoftKeyboard();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("操作失败!" + "\n" + "\n" + ex.Message, "错误");
+ }
+
+ }
+ }
+}
diff --git a/Data/LoginData.cs b/Data/LoginData.cs
new file mode 100644
index 0000000..71d6fba
--- /dev/null
+++ b/Data/LoginData.cs
@@ -0,0 +1,21 @@
+namespace 软胶囊弹性硬度测试仪
+{
+ public class LoginData
+ {
+ static string _userName = "";
+ public string UserName
+ {
+ get { return _userName; }
+ set { _userName = value; }
+ }
+
+ //登陆权限
+ static int _userPower = 0;//0为普通用户,1为管理员
+ public int UserPower
+ {
+ get { return _userPower; }
+ set { _userPower = value; }
+ }
+
+ }
+}
diff --git a/Data/ModbusResourceManager.cs b/Data/ModbusResourceManager.cs
new file mode 100644
index 0000000..5b2e345
--- /dev/null
+++ b/Data/ModbusResourceManager.cs
@@ -0,0 +1,69 @@
+using System;
+using Modbus.Device;
+using System.Net.Sockets;
+
+namespace 软胶囊弹性硬度测试仪.Data
+{
+ // 单例模式:全局唯一资源管理器
+ public class ModbusResourceManager
+ {
+ // 私有构造函数:禁止外部new
+ private ModbusResourceManager() { }
+
+ // 唯一实例
+ private static readonly Lazy _instance = new Lazy(() => new ModbusResourceManager());
+ public static ModbusResourceManager Instance => _instance.Value;
+
+ // 共享资源
+ public TcpClient TcpClient { get; private set; }
+ public IModbusMaster ModbusMaster { get; private set; }
+
+ // 初始化资源(在程序启动时调用,如MainWindow加载时)
+ public bool Init(string ip, int port)
+ {
+ try
+ {
+ // 先释放旧资源
+ ReleaseResource();
+
+ // 创建新连接
+ TcpClient = new TcpClient();
+ TcpClient.Connect(ip, port);
+ ModbusMaster = ModbusIpMaster.CreateIp(TcpClient);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"资源初始化失败:{ex.Message}");
+ ReleaseResource();
+ return false;
+ }
+ }
+
+ public void Dispose()
+ {
+ try
+ {
+ ModbusMaster?.Dispose();
+ TcpClient?.Close();
+ }
+ catch
+ {
+ // 忽略清理时的异常
+ }
+ }
+ // 释放资源(统一释放,避免重复关闭)
+ public void ReleaseResource()
+ {
+ ModbusMaster?.Dispose();
+ ModbusMaster = null;
+
+ //if (TcpClient?.Connected ?? false)
+ //{
+ // TcpClient.Close();
+ //}
+ TcpClient?.Dispose();
+ TcpClient = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Data/PLC_Data.cs b/Data/PLC_Data.cs
new file mode 100644
index 0000000..7d8d671
--- /dev/null
+++ b/Data/PLC_Data.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace 软胶囊弹性硬度测试仪.Data
+{
+ internal class PLC_Data
+ {
+
+ }
+}
diff --git a/Data/keyboard.cs b/Data/keyboard.cs
new file mode 100644
index 0000000..35c8adb
--- /dev/null
+++ b/Data/keyboard.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Security.Principal;
+using System.Windows;
+
+public class KeyboardHelper
+{
+ public static void ShowSoftKeyboard()
+ {
+ if (!IsRunAsAdmin())
+ {
+ RestartAsAdmin();
+ return;
+ }
+
+ // 替换原有的 Process.Start 代码
+ string oskPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "osk.exe");
+ if (File.Exists(oskPath))
+ {
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = oskPath,
+ UseShellExecute = true
+ });
+ }
+ else
+ {
+ //MessageBox.Show("未找到屏幕键盘程序(osk.exe),可能系统文件缺失或非Windows系统。", "错误");
+ }
+ }
+
+ public static void HideSoftKeyboard()
+ {
+ try
+ {
+ Process.Start("cmd.exe", "/C taskkill /IM osk.exe /F");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Error: " + ex.Message);
+ }
+ }
+
+ private static bool IsRunAsAdmin()
+ {
+ WindowsIdentity identity = WindowsIdentity.GetCurrent();
+ WindowsPrincipal principal = new WindowsPrincipal(identity);
+ return principal.IsInRole(WindowsBuiltInRole.Administrator);
+ }
+
+ private static void RestartAsAdmin()
+ {
+ ProcessStartInfo startInfo = new ProcessStartInfo();
+ startInfo.UseShellExecute = true;
+ startInfo.WorkingDirectory = Environment.CurrentDirectory;
+ startInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
+ startInfo.Verb = "runas";
+
+ try
+ {
+ Process.Start(startInfo);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Error: " + ex.Message);
+ }
+
+ Environment.Exit(0);
+ }
+}
diff --git a/EmergencyStopWindow.xaml b/EmergencyStopWindow.xaml
new file mode 100644
index 0000000..78654d0
--- /dev/null
+++ b/EmergencyStopWindow.xaml
@@ -0,0 +1,527 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/EmergencyStopWindow.xaml.cs b/EmergencyStopWindow.xaml.cs
new file mode 100644
index 0000000..323c099
--- /dev/null
+++ b/EmergencyStopWindow.xaml.cs
@@ -0,0 +1,787 @@
+using Modbus.Device;
+using OxyPlot;
+using OxyPlot.Series;
+using OxyPlot.Wpf;
+using PdfSharpCore.Drawing;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using 软胶囊弹性硬度测试仪;
+using 软胶囊弹性硬度测试仪.Data;
+
+namespace EmptyLoadTest
+{
+ ///
+ /// Window1.xaml 的交互逻辑
+ ///
+ public partial class EmergencyStopWindow : Window
+ {
+
+ private ObservableCollection _reportData;
+ private DispatcherTimer _dataInsertTimer;
+ private int _dataIndex = 1;
+ #region 私有字段
+
+ private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient;
+ private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
+
+
+ private readonly DispatcherTimer _readTimer;
+ private DispatcherTimer _dataTimer;
+
+ #endregion
+
+ 软胶囊弹性硬度测试仪.Function ma;
+ DataChange c = new DataChange();
+ private PlotModel _plotModel;
+ private LineSeries _temperatureSeries;
+ public EmergencyStopWindow()
+ {
+ InitializeComponent();
+ InitializeData();
+ InitializeUI();
+ InitializeModbusTcp();
+ _readTimer = InitDispatcherTimer();
+ _dataTimer = InitDispatcherTimer2();
+
+ }
+
+ private void InitializeUI()
+ {
+ // 初始化图表
+ _plotModel = new PlotModel
+ {
+ Title = "扭矩-转速曲线",
+ Subtitle = "医用刨削器特征"
+ };
+
+ _plotModel.Axes.Add(new OxyPlot.Axes.LinearAxis
+ {
+ Position = OxyPlot.Axes.AxisPosition.Bottom,
+ Title = "扭矩(N.cm)",
+ Minimum = 0
+ });
+
+ _plotModel.Axes.Add(new OxyPlot.Axes.LinearAxis
+ {
+ Position = OxyPlot.Axes.AxisPosition.Left,
+ Title = "转速(rad/min)"
+ });
+
+ _temperatureSeries = new LineSeries
+ {
+ Title = "转速变化",
+ Color = OxyColors.Blue,
+ MarkerType = MarkerType.Circle,
+ MarkerSize = 3
+ };
+
+ _plotModel.Series.Add(_temperatureSeries);
+ plotView.Model = _plotModel;
+ }
+
+ private static EmergencyStopWindow _instance;
+ public static EmergencyStopWindow Instance
+ {
+ get
+ {
+ if (_instance == null || !_instance.IsLoaded)
+ {
+ _instance = new EmergencyStopWindow();
+ }
+ return _instance;
+ }
+ }
+
+ private void InitializeModbusTcp()
+ {
+ try
+ {
+
+ string plcIp = "192.168.1.10";
+ bool initSuccess = ModbusResourceManager.Instance.Init(plcIp, 502);
+ if (!initSuccess)
+ {
+ MessageBox.Show("连接Modbus服务器失败!", "错误");
+ this.Close();
+ return;
+ }
+
+ // 检查连接状态
+ if (_tcpClient == null || !_tcpClient.Connected)
+ {
+ MessageBox.Show("Modbus连接异常!", "错误");
+ this.Close();
+ return;
+ }
+
+ ma = new 软胶囊弹性硬度测试仪.Function(_modbusMaster);
+
+ }
+ catch (Exception ex)
+ {
+ ShowError($"Modbus初始化失败: {ex.Message}");
+ }
+ }
+
+ private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+
+
+ private DispatcherTimer InitDispatcherTimer()
+ {
+ var timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(100)
+ };
+ timer.Tick += async (s, e) =>
+ {
+ if (_modbusMaster != null)
+ {
+ try
+ {
+ await ReadAddr262DataAsync();
+ }
+ catch { }
+ }
+ };
+ return timer;
+ }
+
+ private DispatcherTimer InitDispatcherTimer2()
+ {
+ var timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(50)
+ };
+ timer.Tick += DataTimer_Tick;
+
+ return timer;
+ }
+
+ private async System.Threading.Tasks.Task ReadAddr262DataAsync()
+ {
+ try
+ {
+ // 创建任务列表
+ var tasks = new List
+ {
+ ReadAndUpdateFloatAsync(1306, 1, actualSpeed, "F2", " "),
+ ReadAndUpdateFloatAsync(1304, 2, force, "F2", " "),
+ ReadAndUpdateFloatAsync(322, 2, settingforce, "F3", " "),
+ ReadAndUpdateFloatAsync(300, 2, speed, "F3", " "),
+ ReadAndUpdateFloatAsync(430, 2, maxforce, "F2", " "),
+
+ ReadAndUpdateFloatAsync(4324, 1, reachforce, "F0", " "),
+ ReadAndUpdateFloatAsync(4322, 1, maxforce2, "F0", " "),
+ ReadStatusAsync(),
+ ReadresetAndStopStatusAsync()
+ };
+
+ await Task.WhenAll(tasks);
+ }
+ catch (Exception ex)
+ {
+ ShowError($"读取数据失败:{ex.Message}");
+ }
+ }
+
+
+
+ private void updateReport()
+ {
+ // 2. 读取配置文件(App.config)
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+ config.AppSettings.Settings["txtSetTorque"].Value = settingforce.Text;
+ config.AppSettings.Settings["txtTestTime"].Value = (DateTime.Now - starttime).TotalSeconds.ToString("F1");
+ config.AppSettings.Settings["txtSpeedAtSetTorque"].Value = maxforce2.Text;
+ config.AppSettings.Settings["txtSpeedAtMaxTorque"].Value = maxforce2.Text;
+
+ // 4. 保存配置更改(关键:不调用Save则修改不生效)
+ config.Save(ConfigurationSaveMode.Modified);
+ // 刷新配置管理器,让后续读取能获取最新值
+ ConfigurationManager.RefreshSection("appSettings");
+
+ }
+ // 添加这些变量
+ private bool _testStarted = false;
+ private bool _testCompleted = false;
+ private async Task ReadStatusAsync()
+ {
+ try
+ {
+ bool[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadCoilsAsync(1, 321, 1)
+ );
+
+ if (registers != null && registers.Length >= 1)
+ {
+ bool value = registers[0];
+ Dispatcher.Invoke(() =>
+ {
+ if (value)
+ {
+ statusB.Background = Brushes.Green;
+ status.Text = "运行中";
+
+ _dataInsertTimer?.Start();
+ _dataTimer?.Start();
+ updateReport();
+
+ // 测试已开始
+ if (!_testStarted)
+ {
+ _testStarted = true;
+ }
+ }
+ else
+ {
+ statusB.Background = Brushes.Blue;
+ status.Text = "空闲";
+
+ // 只有当测试确实开始过且尚未完成时才导出
+ if (_testStarted && !_testCompleted)
+ {
+ _testCompleted = true;
+
+ // 检查是否有测试数据
+ if (_reportData != null && _reportData.Count > 0)
+ {
+ // 延时一小段时间确保数据已保存
+ Task.Delay(500).ContinueWith(_ =>
+ {
+ Dispatcher.Invoke(async () =>
+ {
+ await AutoExportCSV();
+ });
+ });
+ }
+ }
+
+ _dataInsertTimer?.Stop();
+ _dataTimer?.Stop();
+ }
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{200}失败:{ex.Message}");
+ }
+ }
+
+ private void InitializeData()
+ {
+ _reportData = new ObservableCollection();
+ _dataInsertTimer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(20) // 每秒插入一次数据
+ };
+ _dataInsertTimer.Tick += InsertData_Tick;
+ }
+ // 添加线程锁,防止并发问题
+ private readonly object _dataLock = new object();
+ private int _lastForceValueIndex = 0;
+ private float _lastForceValue = 0f;
+ private const float FORCE_CHANGE_THRESHOLD = 0.1f; // 力变化阈值,防止重复记录
+
+ private void InsertData_Tick(object sender, EventArgs e)
+ {
+ try
+ {
+ // 解析当前力值
+ if (!float.TryParse(force.Text, out float currentForceValue))
+ {
+ currentForceValue = 0;
+ }
+ //ushort[] registers = _modbusMaster?.ReadHoldingRegisters(1, 1304, 2);
+
+
+ //if (registers != null && registers.Length >= 2)
+ //{
+ // currentForceValue = c.UshortToFloat(registers[1], registers[0]);
+
+ //}
+
+ if (!float.TryParse(actualSpeed.Text, out float currentSpeedValue))
+ {
+ currentSpeedValue = 0;
+ }
+
+ // 简化条件:去掉阈值限制或降低第一次记录的阈值
+ if (_reportData.Count == 0 || currentForceValue >= 0.2f)
+ {
+ // 使用锁确保线程安全
+ lock (_dataLock)
+ {
+ // 更新最后记录的值
+ _lastForceValue = currentForceValue;
+ _lastForceValueIndex = _dataIndex;
+
+ // 创建报表项
+ var reportItem = new ReportItem
+ {
+ Index = _dataIndex,
+ Time = DateTime.Now,
+ Torque = currentForceValue,
+ Speed = (int)currentSpeedValue,
+ };
+
+ // 限制最大数据条数,避免内存过大
+ if (_reportData.Count > 1000)
+ {
+ _reportData.RemoveAt(0);
+ }
+
+ // 添加到报表数据
+ _reportData.Add(reportItem);
+
+ // 递增索引
+ _dataIndex++;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"插入数据失败:{ex.Message}");
+ }
+ }
+ public ObservableCollection GetReportData()
+ {
+ return _reportData;
+ }
+
+ // 清空报表数据
+ public void ClearReportData()
+ {
+ _reportData?.Clear();
+ _dataIndex = 1;
+ }
+
+ private async Task ReadresetAndStopStatusAsync()
+ {
+ try
+ {
+ bool[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadCoilsAsync(1, 91, 2)
+ );
+
+ if (registers != null && registers.Length >= 1)
+ {
+ bool value = registers[0];
+ Dispatcher.Invoke(() =>
+ {
+ if (value)
+ {
+ fastleftB.Background = Brushes.Red;
+ fastleft.Text = "复位中";
+ }
+ else if (registers[1])
+ {
+ fastleftB.Background = Brushes.Green;
+ fastleft.Text = "复位完成";
+ shacheB.Visibility = Visibility.Hidden;
+ }
+ });
+ }
+
+
+
+ bool[] registers2 = await Task.Run(async () =>
+ await _modbusMaster?.ReadCoilsAsync(1, 310, 1)
+);
+
+ if (registers2 != null && registers2.Length >= 1)
+ {
+ bool value2 = registers2[0];
+ Dispatcher.Invoke(() =>
+ {
+ if (value2)
+ {
+
+ limit.Visibility = Visibility.Visible;
+ }
+ else
+ {
+
+ limit.Visibility = Visibility.Hidden;
+ }
+ });
+ }
+
+
+
+
+
+ bool[] registers3 = await Task.Run(async () =>
+ await _modbusMaster?.ReadCoilsAsync(1, 1300, 1)
+);
+
+ if (registers3 != null && registers3.Length >= 1)
+ {
+ bool value3 = registers3[0];
+ Dispatcher.Invoke(() =>
+ {
+ if (value3)
+ {
+ stopB.Background = Brushes.Red;
+ stop.Text = "急停未复位";
+ faststop.Visibility = Visibility.Visible;
+ }
+ else
+ {
+
+ stopB.Background = Brushes.Green;
+ stop.Text = "急停已复位,系统可重新运行";
+ faststop.Visibility = Visibility.Hidden;
+ }
+ });
+ }
+
+
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{200}失败:{ex.Message}");
+ }
+ }
+ private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBox control, string format, string unit)
+ {
+ try
+ {
+ ushort[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
+ );
+
+ if (registers != null && registers.Length >= 2)
+ {
+ float value = c.UshortToFloat(registers[1], registers[0]);
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ else if (registers != null && registers.Length >= 1)
+ {
+ int value = registers[0];
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
+ }
+ }
+
+ private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBlock control, string format, string unit)
+ {
+ try
+ {
+ ushort[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
+ );
+
+ if (registers != null && registers.Length >= 2)
+ {
+ float value = c.UshortToFloat(registers[1], registers[0]);
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ else if (registers != null && registers.Length >= 1)
+ {
+ int value = registers[0];
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
+ }
+ }
+
+
+ private void settingforce_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(settingforce.Text.Trim(), 322, Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void speed_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(speed.Text.Trim(), 300, Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ //ma.BtnClickFunctionForNew(Function.ButtonType.置位型, 300);
+ }
+
+ private void Button_Click_1(object sender, RoutedEventArgs e)
+ {
+ //ma.BtnClickFunctionForNew(Function.ButtonType.置位型, 301);
+ }
+
+ private void Button_Click_2(object sender, RoutedEventArgs e)
+ {
+ ma.BtnClickFunctionForNew(Function.ButtonType.置位型, 320);
+
+ starttime = DateTime.Now;
+ // 重置测试状态标志
+ _testStarted = true;
+ _testCompleted = false;
+ _reportData?.Clear(); // 清空之前的测试数据
+ _dataIndex = 1;
+ }
+ DateTime starttime;
+ private readonly Queue _forceBuffer = new Queue();
+ private readonly Queue _speedBuffer = new Queue();
+ private const int BUFFER_SIZE = 5; // 滑动窗口大小
+
+ private void DataTimer_Tick(object sender, EventArgs e)
+ {
+ float forceV = float.Parse(force.Text);
+ float actualSpeedV = float.Parse(actualSpeed.Text);
+ float settingforceV = float.Parse(settingforce.Text);
+
+ _temperatureSeries.Points.Add(new OxyPlot.DataPoint(forceV, actualSpeedV));
+
+ _plotModel.InvalidatePlot(true);
+
+
+ //CurveWindow.Instance.UpdateData(forceV, actualSpeedV);
+
+ if (forceV + 1 >= settingforceV)
+ {
+ shacheB.Visibility = Visibility.Visible;
+ shacheB.Background = Brushes.Red;
+ shache.Text = "请松踏板!!";
+ }
+ }
+ private void Button_Click_3(object sender, RoutedEventArgs e)
+ {
+ ma.BtnClickFunctionForNew(Function.ButtonType.复归型, 90);
+ //shacheB.Visibility = Visibility.Hidden;
+ }
+
+ private void Button_Click_4(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = ExperimentReportWindow.Instance;
+
+ // 检查窗口状态,只在窗口未显示时调用ShowDialog
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ // 如果窗口已显示,可将其激活到前台
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ private void Button_Click_5(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = ProcessReportWindow.Instance;
+
+ // 检查窗口状态,只在窗口未显示时调用ShowDialog
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ // 如果窗口已显示,可将其激活到前台
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ _readTimer?.Start();
+ }
+
+ private void 上升_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ _modbusMaster?.WriteSingleCoil(1, 300, true);
+
+ ((Button)sender).CaptureMouse();
+ }
+
+ private void 上升_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ _modbusMaster?.WriteSingleCoil(1, 300, false);
+
+ ((Button)sender).ReleaseMouseCapture();
+ }
+
+ private void 上升_LostMouseCapture(object sender, MouseEventArgs e)
+ {
+ _modbusMaster?.WriteSingleCoil(1, 300, false);
+ }
+
+
+ // 鼠标按下时触发
+ private void 下降_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ // 鼠标按下时置位
+ _modbusMaster?.WriteSingleCoil(1, 301, true);
+
+ // 捕获鼠标,确保即使拖动出按钮范围也能收到抬起事件
+ ((Button)sender).CaptureMouse();
+ }
+
+ private void 下降_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ // 鼠标抬起时复位
+ _modbusMaster?.WriteSingleCoil(1, 301, false);
+
+ // 释放鼠标捕获
+ ((Button)sender).ReleaseMouseCapture();
+ }
+
+ private void 下降_LostMouseCapture(object sender, MouseEventArgs e)
+ {
+ // 如果意外失去鼠标捕获,也复位
+ _modbusMaster?.WriteSingleCoil(1, 301, false);
+ }
+
+ private void Button_Click_6(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = MainWindow.Instance;
+
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ private void Button_Click_7(object sender, RoutedEventArgs e)
+ {
+ _temperatureSeries?.Points.Clear();
+ // 如果使用了滑动窗口缓冲区,也需要清除
+ if (_forceBuffer != null) _forceBuffer.Clear();
+ if (_speedBuffer != null) _speedBuffer.Clear();
+ _dataIndex = 0;
+ // 刷新图表
+ _plotModel?.InvalidatePlot(true);
+ }
+
+ private void Button_Click_8(object sender, RoutedEventArgs e)
+ {
+ SaveChartAsImage();
+ }
+
+ private void SaveChartAsImage()
+ {
+ try
+ {
+ int imageWidth = 1000; // 设置宽度
+ int imageHeight = 700; // 设置高度
+ if (plotView == null || _temperatureSeries.Points.Count == 0)
+ {
+ MessageBox.Show("没有数据可保存", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ var saveFileDialog = new Microsoft.Win32.SaveFileDialog
+ {
+ Filter = "PNG图片 (*.png)|*.png",
+ FileName = $"曲线图_{DateTime.Now:yyyyMMdd_HHmmss}.png",
+ DefaultExt = ".png"
+ };
+
+ if (saveFileDialog.ShowDialog() == true)
+ {
+ // 方法1:直接截图plotView控件
+ RenderTargetBitmap renderBitmap = new RenderTargetBitmap(
+ imageWidth,
+ imageHeight,
+ 96d, 96d, PixelFormats.Pbgra32);
+
+ renderBitmap.Render(plotView);
+
+ // 保存为PNG
+ using (var fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create))
+ {
+ PngBitmapEncoder encoder = new PngBitmapEncoder();
+ encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
+ encoder.Save(fileStream);
+ }
+
+ MessageBox.Show($"图片已保存到:{saveFileDialog.FileName}", "保存成功",
+ MessageBoxButton.OK, MessageBoxImage.Information);
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"保存失败:{ex.Message}", "错误",
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+
+ private async Task AutoExportCSV()
+ {
+ try
+ {
+ // 再次检查是否有测试数据
+ if (_reportData == null || _reportData.Count == 0)
+ {
+ return;
+ }
+
+ string fileName = $"过程报表_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
+ string folderPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Reports");
+ Directory.CreateDirectory(folderPath);
+ string filePath = System.IO.Path.Combine(folderPath, fileName);
+
+ await Task.Run(() =>
+ {
+ using (var writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8))
+ {
+ writer.WriteLine("序号,时间,实时扭矩(N.cm),实时转速(Rad/Min)");
+
+ foreach (var item in _reportData)
+ {
+ writer.WriteLine($"{item.Index},{item.Time:HH:mm:ss},{item.Torque:F1},{item.Speed}");
+ }
+ }
+ });
+
+ Dispatcher.Invoke(() =>
+ {
+ MessageBox.Show($"测试完成,报表已自动导出到:{filePath}", "导出成功",
+ MessageBoxButton.OK, MessageBoxImage.Information);
+ });
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"自动导出报表失败:{ex.Message}");
+ }
+ }
+ }
+}
diff --git a/ExperimentReportWindow.xaml b/ExperimentReportWindow.xaml
new file mode 100644
index 0000000..d91311c
--- /dev/null
+++ b/ExperimentReportWindow.xaml
@@ -0,0 +1,582 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ExperimentReportWindow.xaml.cs b/ExperimentReportWindow.xaml.cs
new file mode 100644
index 0000000..cfc3be1
--- /dev/null
+++ b/ExperimentReportWindow.xaml.cs
@@ -0,0 +1,262 @@
+using Microsoft.Win32;
+using Modbus.Device;
+using System;
+using System.Configuration;
+using System.Diagnostics;
+using System.IO;
+using System.Net.Sockets;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using 软胶囊弹性硬度测试仪.Data;
+
+namespace EmptyLoadTest
+{
+
+ public partial class ExperimentReportWindow : Window
+ {
+
+ private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient;
+ private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
+
+
+
+ // 2. 改为公共可读写属性(核心:外部可直接修改)
+ public ExperimentReportData ReportData { get; set; }
+
+
+ // 无参构造(方便单例创建,默认初始化空数据)
+ public ExperimentReportWindow()
+ {
+ InitializeComponent();
+ ReportData = new ExperimentReportData();
+ }
+
+ // 简化的导出方法 - 只导出为文本和CSV格式
+ private void ExportReport_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ SaveFileDialog saveFileDialog = new SaveFileDialog
+ {
+ Filter = "CSV文件 (*.csv)|*.csv",
+ FileName = $"实验报告_{DateTime.Now:yyyyMMdd_HHmmss}",
+ DefaultExt = ".csv",
+ Title = "保存实验报告"
+ };
+
+ if (saveFileDialog.ShowDialog() == true)
+ {
+ string filePath = saveFileDialog.FileName;
+ string fileExt = Path.GetExtension(filePath).ToLower();
+
+ if (fileExt == ".csv")
+ {
+ ExportToCsvFile(filePath);
+ }
+
+ var result = MessageBox.Show("报告导出成功!\n是否要打开文件?",
+ "导出成功", MessageBoxButton.YesNo, MessageBoxImage.Information);
+
+ if (result == MessageBoxResult.Yes)
+ {
+ Process.Start(new ProcessStartInfo(filePath) { UseShellExecute = true });
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"导出失败:{ex.Message}", "错误",
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+ // 导出为CSV文件
+ private void ExportToCsvFile(string filePath)
+ {
+ using (StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8))
+ {
+ writer.WriteLine("项目,数值,单位");
+ writer.WriteLine($"设置转速,{ReportData.SetSpeed:F1},转/分钟");
+ writer.WriteLine($"实际转速1,{ReportData.ActualSpeed1:F1},转/分钟");
+ writer.WriteLine($"实际转速2,{ReportData.ActualSpeed2:F1},转/分钟");
+ writer.WriteLine($"实际转速3,{ReportData.ActualSpeed3:F1},转/分钟");
+ writer.WriteLine($"设置往复频率,{ReportData.SetFrequency:F0},次/分钟");
+ writer.WriteLine($"实际往复频率1,{ReportData.ActualFrequency1:F0},次/分钟");
+ writer.WriteLine($"实际往复频率2,{ReportData.ActualFrequency2:F0},次/分钟");
+ writer.WriteLine($"实际往复频率3,{ReportData.ActualFrequency3:F0},次/分钟");
+ writer.WriteLine($"设置额定扭矩,{ReportData.SetTorque:F1},N.cm");
+ writer.WriteLine($"测试时间,{ReportData.TestTime},秒");
+ writer.WriteLine($"到达设定扭矩时的转速,{ReportData.SpeedAtSetTorque:F0},转/分钟");
+ writer.WriteLine($"最大扭矩时的转速,{ReportData.SpeedAtMaxTorque:F0},转/分钟");
+ }
+ }
+
+ // 简化的打印预览
+ private void PrintPreview_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ PrintDialog printDialog = new PrintDialog();
+
+ // 创建简单的打印文档
+ FlowDocument doc = new FlowDocument();
+ doc.Blocks.Add(new Paragraph(new Run("实验报告")));
+ doc.Blocks.Add(new Paragraph(new Run("")));
+ doc.Blocks.Add(new Paragraph(new Run($"样品编号:{ReportData.SampleId}")));
+ doc.Blocks.Add(new Paragraph(new Run($"测试日期:{ReportData.TestDate:yyyy年MM月dd日}")));
+
+ if (printDialog.ShowDialog() == true)
+ {
+ printDialog.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator, "实验报告");
+ MessageBox.Show("打印作业已发送到打印机。", "打印成功");
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"打印失败:{ex.Message}", "错误");
+ }
+ }
+
+ // 打开文件夹按钮点击事件
+ private void OpenFolder_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ System.Diagnostics.Process.Start("explorer.exe", @"C:\");
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"打开文件夹失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+
+ // 返回按钮点击事件
+ private void Return_Click(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = MainWindow.Instance;
+
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ // 3. 修正单例逻辑:确保单例的 ReportData 可被外部修改,不丢失数据
+ private static ExperimentReportWindow _instance;
+ // 加锁保证线程安全
+ private static readonly object _lock = new object();
+ public static ExperimentReportWindow Instance
+ {
+ get
+ {
+ lock (_lock)
+ {
+ if (_instance == null || !_instance.IsLoaded)
+ {
+ _instance = new ExperimentReportWindow(); // 使用无参构造,初始化空数据
+ }
+ return _instance;
+ }
+ }
+ }
+
+ // 3. 修正单例逻辑:确保单例的 ReportData 可被外部修改,不丢失数据
+ private static TorqueParameterWindow _instance2;
+ // 加锁保证线程安全
+ private static readonly object _lock2 = new object();
+ public static TorqueParameterWindow Instance2
+ {
+ get
+ {
+ lock (_lock2)
+ {
+ if (_instance2 == null || !_instance2.IsLoaded)
+ {
+ _instance2 = new TorqueParameterWindow(); // 使用无参构造,初始化空数据
+ }
+ return _instance2;
+ }
+ }
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+
+ ReportData.SetSpeed = double.Parse(config.AppSettings.Settings["SettingSpeed"].Value);
+ ReportData.ActualSpeed1 = double.Parse(config.AppSettings.Settings["ActualSpeed1"].Value);
+ ReportData.ActualSpeed2 = double.Parse(config.AppSettings.Settings["ActualSpeed2"].Value);
+ ReportData.ActualSpeed3 = double.Parse(config.AppSettings.Settings["ActualSpeed3"].Value);
+
+
+ ReportData.SetFrequency = double.Parse(config.AppSettings.Settings["interval"].Value);
+ ReportData.ActualFrequency1 = double.Parse(config.AppSettings.Settings["interval1"].Value);
+ ReportData.ActualFrequency2 = double.Parse(config.AppSettings.Settings["interval2"].Value);
+ ReportData.ActualFrequency3 = double.Parse(config.AppSettings.Settings["interval3"].Value);
+
+
+ txtSetSpeed.Text = ReportData.SetSpeed.ToString();
+ txtActualSpeed1.Text = ReportData.ActualSpeed1.ToString();
+ txtActualSpeed2.Text = ReportData.ActualSpeed2.ToString();
+ txtActualSpeed3.Text = ReportData.ActualSpeed3.ToString();
+ txtSetFrequency.Text = ReportData.SetFrequency.ToString();
+ txtActualFrequency1.Text = ReportData.ActualFrequency1.ToString();
+ txtActualFrequency2.Text = ReportData.ActualFrequency2.ToString();
+ txtActualFrequency3.Text = ReportData.ActualFrequency3.ToString();
+
+
+ ReportData.SetTorque = double.Parse(config.AppSettings.Settings["txtSetTorque"].Value);
+ ReportData.TestTime = float.Parse(config.AppSettings.Settings["txtTestTime"].Value);
+ ReportData.SpeedAtSetTorque = double.Parse(config.AppSettings.Settings["txtSpeedAtSetTorque"].Value);
+ ReportData.SpeedAtMaxTorque = double.Parse(config.AppSettings.Settings["txtSpeedAtMaxTorque"].Value);
+
+
+
+
+ txtSetTorque.Text = ReportData.SetTorque.ToString();
+ txtTestTime.Text = ReportData.TestTime.ToString();
+ txtSpeedAtSetTorque.Text = ReportData.SpeedAtSetTorque.ToString();
+ txtSpeedAtMaxTorque.Text = ReportData.SpeedAtMaxTorque.ToString();
+ }
+ }
+}
+
+// 1. 提取为独立类(外部可直接创建/修改,无需嵌套访问)
+public class ExperimentReportData
+{
+ // 样品信息
+ public string SampleId { get; set; } = "";
+ public DateTime TestDate { get; set; } = DateTime.Today;
+ public string Tester { get; set; } = "";
+ public string DeviceId { get; set; } = "";
+
+ // 空载测试
+ public double SetSpeed { get; set; } = 0;
+ public double ActualSpeed1 { get; set; } = 0;
+ public double ActualSpeed2 { get; set; } = 0;
+ public double ActualSpeed3 { get; set; } = 0;
+ public double SetFrequency { get; set; } = 0;
+ public double ActualFrequency1 { get; set; } = 0;
+ public double ActualFrequency2 { get; set; } = 0;
+ public double ActualFrequency3 { get; set; } = 0;
+
+ // 负载测试
+ public double SetTorque { get; set; } = 0;
+ public float TestTime { get; set; } = 0;
+ public double SpeedAtSetTorque { get; set; } = 0;
+ public double SpeedAtMaxTorque { get; set; } = 0;
+
+ // 测试结论
+ public string Conclusion { get; set; } =
+ "空载测试:转速和往复频率均在允许误差范围内,设备运行正常。\n" +
+ "负载测试:设备在额定扭矩下运行稳定,扭矩-转速曲线符合设计要求。\n" +
+ "总体评价:测试合格,设备性能良好。";
+}
diff --git a/MainWindow.xaml b/MainWindow.xaml
new file mode 100644
index 0000000..2cb6cb9
--- /dev/null
+++ b/MainWindow.xaml
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
new file mode 100644
index 0000000..6df3cfb
--- /dev/null
+++ b/MainWindow.xaml.cs
@@ -0,0 +1,472 @@
+using Modbus.Device;
+using System.Configuration;
+using System.Net.Http;
+using System.Net.Sockets;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using 医用刨削器特征新版8;
+using 软胶囊弹性硬度测试仪;
+using 软胶囊弹性硬度测试仪.Data;
+
+
+namespace EmptyLoadTest
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+
+ #region 私有字段
+
+ private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient;
+ private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
+
+
+
+ private readonly DispatcherTimer _readTimer;
+
+ #endregion
+
+ 软胶囊弹性硬度测试仪.Function ma;
+ DataChange c = new DataChange();
+ public MainWindow()
+ {
+ InitializeComponent();
+ InitializeModbusTcp();
+ _readTimer = InitDispatcherTimer();
+ }
+
+ private static MainWindow _instance;
+ public static MainWindow Instance
+ {
+ get
+ {
+ if (_instance == null || !_instance.IsLoaded)
+ {
+ _instance = new MainWindow();
+ }
+ return _instance;
+ }
+ }
+
+ private void InitializeModbusTcp()
+ {
+ try
+ {
+
+ string plcIp = "192.168.1.10";
+ bool initSuccess = ModbusResourceManager.Instance.Init(plcIp, 502);
+ if (!initSuccess)
+ {
+ MessageBox.Show("连接Modbus服务器失败!", "错误");
+ this.Close();
+ return;
+ }
+
+ // 检查连接状态
+ if (_tcpClient == null || !_tcpClient.Connected)
+ {
+ MessageBox.Show("Modbus连接异常!", "错误");
+ this.Close();
+ return;
+ }
+
+ ma = new Function(_modbusMaster);
+
+ }
+ catch (Exception ex)
+ {
+ ShowError($"Modbus初始化失败: {ex.Message}");
+ }
+ }
+
+ private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+
+
+ private DispatcherTimer InitDispatcherTimer()
+ {
+ var timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(50)
+ };
+ timer.Tick += async (s, e) =>
+ {
+ if (_modbusMaster != null)
+ {
+ try
+ {
+ await ReadAddr262DataAsync();
+ }
+ catch { }
+ }
+ };
+ return timer;
+ }
+
+ private async System.Threading.Tasks.Task ReadAddr262DataAsync()
+ {
+ try
+ {
+ // 增强的空值检查和连接测试
+ if (_modbusMaster == null || _tcpClient == null)
+ {
+ System.Diagnostics.Debug.WriteLine("Modbus客户端为空");
+ return;
+ }
+
+ // 测试连接是否真的可用
+ if (!_tcpClient.Connected)
+ {
+ System.Diagnostics.Debug.WriteLine("TCP连接已断开");
+ // 尝试重新初始化
+ await Dispatcher.BeginInvoke(() => InitializeModbusTcp());
+ return;
+ }
+
+ // 创建任务列表
+ var tasks = new List
+ {
+ ReadAndUpdateFloatAsync(18, 1, intrval2, "F0", " "),
+ };
+
+ await Task.WhenAll(tasks);
+ }
+ catch (SocketException sockEx)
+ {
+ System.Diagnostics.Debug.WriteLine($"Socket异常: {sockEx.Message}");
+ // 网络异常,尝试重新连接
+ await Dispatcher.BeginInvoke(() =>
+ {
+ MessageBox.Show("网络连接异常,尝试重新连接...", "提示",
+ MessageBoxButton.OK, MessageBoxImage.Warning);
+ InitializeModbusTcp();
+ });
+ }
+ catch (Exception ex)
+ {
+ ShowError($"读取数据失败:{ex.Message}");
+ }
+ }
+
+ private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBox control, string format, string unit)
+ {
+ try
+ {
+ // 添加空值检查
+ if (_modbusMaster == null || _tcpClient == null || !_tcpClient.Connected)
+ {
+ return;
+ }
+ ushort[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
+ );
+
+ if (registers != null && registers.Length >= 2)
+ {
+ float value = c.UshortToFloat(registers[1], registers[0]);
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ else if (registers != null && registers.Length >= 1)
+ {
+ int value = registers[0];
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
+ }
+ }
+
+ private void settingspeed_GotFocus(object sender, RoutedEventArgs e)
+ {
+ string dd = settingspeed.Text.Trim();
+ //ma.WriteToPLCForNew(settingspeed.Text.Trim(), 1334, Function.DataType.浮点型);
+ //System.Threading.Tasks.Task.Delay(50);
+ //_isManualInput = false; // 写入后恢复读取
+ //t0.Focus();
+ }
+
+ int i = 1;
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+
+ try
+ {
+
+ // 1. 获取文本框值(去除首尾空格,避免空值)
+ string speed = settingspeed.Text?.Trim() ?? string.Empty;
+ string speed2 = actualspeed.Text?.Trim() ?? string.Empty;
+ string interval2 = interval.Text?.Trim() ?? string.Empty;
+ // 校验值(可选,根据业务需求调整)
+ if (string.IsNullOrEmpty(speed) || string.IsNullOrEmpty(speed2))
+ {
+ MessageBox.Show("速度值不能为空!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ if (i > 3)
+ i = 1;
+ // 2. 读取配置文件(App.config)
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+
+ // 3. 写入/更新配置项
+ // 配置项1:设置速度(键名可自定义,如 "SettingSpeed")
+ if (config.AppSettings.Settings["SettingSpeed"] == null)
+ {
+ // 配置项不存在则新增
+ config.AppSettings.Settings.Add("SettingSpeed", speed);
+ }
+ else
+ {
+ // 配置项已存在则更新值
+ config.AppSettings.Settings["SettingSpeed"].Value = speed;
+ }
+
+
+ // 配置项2:实际速度(键名:"ActualSpeed")
+ if (config.AppSettings.Settings["interval"] == null)
+ {
+ config.AppSettings.Settings.Add("interval", interval2);
+ }
+ else
+ {
+ config.AppSettings.Settings["interval"].Value = interval2;
+ }
+
+ if (i == 1)
+ {
+ config.AppSettings.Settings["ActualSpeed1"].Value = speed2;
+ }
+ else if (i == 2)
+ {
+ config.AppSettings.Settings["ActualSpeed2"].Value = speed2;
+ }
+ else if (i == 3)
+ {
+ config.AppSettings.Settings["ActualSpeed3"].Value = speed2;
+ }
+
+ status.Text = i.ToString();
+ // 4. 保存配置更改(关键:不调用Save则修改不生效)
+ config.Save(ConfigurationSaveMode.Modified);
+ // 刷新配置管理器,让后续读取能获取最新值
+ ConfigurationManager.RefreshSection("appSettings");
+ if (i == 3)
+ {
+ MessageBox.Show("3次记录已保存");
+ }
+ i++;
+ }
+ catch (ConfigurationErrorsException ex)
+ {
+ // 捕获配置文件操作异常(如权限不足、文件损坏)
+ MessageBox.Show($"配置文件写入失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ catch (Exception ex)
+ {
+ // 捕获其他异常
+ MessageBox.Show($"保存失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+ private void intrval2_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(intrval2.Text.Trim(), 18, 软胶囊弹性硬度测试仪.Function.DataType.整形);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void Button_Click_1(object sender, RoutedEventArgs e)
+ {
+ ma.BtnClickFunctionForNew(Function.ButtonType.复归型, 200);
+ }
+
+ private void Button_Click_2(object sender, RoutedEventArgs e)
+ {
+ ma.BtnClickFunctionForNew(Function.ButtonType.复归型, 200);
+ }
+
+
+
+ int j = 1;
+ private void Button_Click_4(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+
+
+ string interval_ = interval.Text?.Trim() ?? string.Empty;
+
+ string interval2_ = intrval2.Text?.Trim() ?? string.Empty;
+
+ if (j > 3)
+ j = 1;
+ // 2. 读取配置文件(App.config)
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+
+
+
+ // 配置项2:实际速度(键名:"ActualSpeed")
+ if (config.AppSettings.Settings["interval"] == null)
+ {
+ config.AppSettings.Settings.Add("interval", interval_);
+ }
+ else
+ {
+ config.AppSettings.Settings["interval"].Value = interval_;
+ }
+
+
+
+ if (j == 1)
+ {
+ config.AppSettings.Settings["interval1"].Value = interval2_;
+ }
+ else if (j == 2)
+ {
+ config.AppSettings.Settings["interval2"].Value = interval2_;
+ }
+ else if (j == 3)
+ {
+ config.AppSettings.Settings["interval3"].Value = interval2_;
+ }
+ status.Text = j.ToString();
+ // 4. 保存配置更改(关键:不调用Save则修改不生效)
+ config.Save(ConfigurationSaveMode.Modified);
+ // 刷新配置管理器,让后续读取能获取最新值
+ ConfigurationManager.RefreshSection("appSettings");
+ if (j == 3)
+ {
+ MessageBox.Show("3次记录已保存");
+ }
+ j++;
+
+ }
+ catch (ConfigurationErrorsException ex)
+ {
+ // 捕获配置文件操作异常(如权限不足、文件损坏)
+ MessageBox.Show($"配置文件写入失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ catch (Exception ex)
+ {
+ // 捕获其他异常
+ MessageBox.Show($"保存失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+
+ private void LoadTestMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = EmergencyStopWindow.Instance;
+
+ // 检查窗口状态,只在窗口未显示时调用ShowDialog
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ // 如果窗口已显示,可将其激活到前台
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ private void ReportMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+
+ var mainWindow = ExperimentReportWindow.Instance;
+
+ // 检查窗口状态,只在窗口未显示时调用ShowDialog
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ // 如果窗口已显示,可将其激活到前台
+ mainWindow.Activate();
+ }
+
+ Close();
+
+ }
+
+ private void MenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ // 停止所有定时器
+ _readTimer?.Stop();
+
+
+ // 关闭Modbus连接
+ if (_modbusMaster != null)
+ {
+ _modbusMaster.Dispose();
+ }
+
+ // 关闭TCP连接
+ if (_tcpClient != null && _tcpClient.Connected)
+ {
+ _tcpClient.Close();
+ }
+
+ // 如果是主窗口,退出程序
+ Application.Current.Shutdown();
+
+ // 或者关闭当前窗口
+ // this.Close();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"退出程序时出错:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ _readTimer?.Start();
+
+
+
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+
+ settingspeed.Text = config.AppSettings.Settings["SettingSpeed"].Value;
+
+ actualspeed.Text = config.AppSettings.Settings["ActualSpeed1"].Value;
+
+ interval.Text = config.AppSettings.Settings["ActualSpeed1"].Value;
+ }
+
+ private void Button_Click_3(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = TorqueParameterWindow.Instance;
+
+ // 检查窗口状态,只在窗口未显示时调用ShowDialog
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ // 如果窗口已显示,可将其激活到前台
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ProcessReportWindow.xaml b/ProcessReportWindow.xaml
new file mode 100644
index 0000000..c5f7bb1
--- /dev/null
+++ b/ProcessReportWindow.xaml
@@ -0,0 +1,498 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ProcessReportWindow.xaml.cs b/ProcessReportWindow.xaml.cs
new file mode 100644
index 0000000..8f6e979
--- /dev/null
+++ b/ProcessReportWindow.xaml.cs
@@ -0,0 +1,411 @@
+
+using PdfSharpCore.Drawing;
+using PdfSharpCore.Pdf;
+using PdfSharpCore.Utils;
+using System;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Media;
+
+namespace EmptyLoadTest
+{
+ // 数据模型
+ public class ReportItem
+ {
+ public int Index { get; set; }
+ public DateTime Time { get; set; }
+ public double Torque { get; set; }
+ public int Speed { get; set; }
+ public double Pressure { get; set; }
+ public string Status { get; set; }
+ public string Notes { get; set; }
+ }
+
+ // 状态到颜色的转换器
+ public class StatusToColorConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is string status)
+ {
+ return status switch
+ {
+ //"正常" => new SolidColorBrush(Color.FromRgb(39, 174, 96)), // 绿色
+ //"警告" => new SolidColorBrush(Color.FromRgb(230, 126, 34)), // 橙色
+ //"错误" => new SolidColorBrush(Color.FromRgb(231, 76, 60)), // 红色
+ _ => new SolidColorBrush(Color.FromRgb(52, 73, 94)) // 默认深蓝色
+ };
+ }
+ return new SolidColorBrush(Color.FromRgb(52, 73, 94));
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ // 视图模型
+ public class ReportViewModel : INotifyPropertyChanged
+ {
+ private ObservableCollection _reportData;
+ public ObservableCollection ReportData
+ {
+ get => _reportData;
+ set
+ {
+ _reportData = value;
+ OnPropertyChanged(nameof(ReportData));
+ UpdateStatistics();
+ }
+ }
+
+ private int _dataCount;
+ public int DataCount
+ {
+ get => _dataCount;
+ set
+ {
+ _dataCount = value;
+ OnPropertyChanged(nameof(DataCount));
+ }
+ }
+
+ private int _normalCount;
+ public int NormalCount
+ {
+ get => _normalCount;
+ set
+ {
+ _normalCount = value;
+ OnPropertyChanged(nameof(NormalCount));
+ }
+ }
+
+ private int _warningCount;
+ public int WarningCount
+ {
+ get => _warningCount;
+ set
+ {
+ _warningCount = value;
+ OnPropertyChanged(nameof(WarningCount));
+ }
+ }
+
+ private int _errorCount;
+ public int ErrorCount
+ {
+ get => _errorCount;
+ set
+ {
+ _errorCount = value;
+ OnPropertyChanged(nameof(ErrorCount));
+ }
+ }
+
+ public ReportViewModel(ObservableCollection realData = null)
+ {
+ if (realData != null && realData.Count > 0)
+ {
+ // 使用传入的真实数据
+ ReportData = realData;
+
+
+ }
+
+ UpdateStatistics();
+ }
+
+ private void UpdateStatistics()
+ {
+ if (ReportData == null) return;
+
+ DataCount = ReportData.Count;
+ //NormalCount = ReportData.Count(item => item.Status == "正常");
+ //WarningCount = ReportData.Count(item => item.Status == "警告");
+ //ErrorCount = ReportData.Count(item => item.Status == "错误");
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+ protected virtual void OnPropertyChanged(string propertyName)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ // 在 ReportViewModel 类中添加这个方法
+ public void ExportData()
+ {
+ try
+ {
+ var saveDialog = new Microsoft.Win32.SaveFileDialog
+ {
+ Filter = "CSV文件|*.csv",
+ FileName = $"过程报表_{DateTime.Now:yyyyMMdd_HHmmss}.csv",
+ Title = "导出报表"
+ };
+
+ if (saveDialog.ShowDialog() == true)
+ {
+ using (var writer = new StreamWriter(saveDialog.FileName, false, System.Text.Encoding.UTF8))
+ {
+ writer.WriteLine("序号,时间,实时扭矩(N.cm),实时转速(Rad/Min)");
+
+ foreach (var item in ReportData)
+ {
+ writer.WriteLine($"{item.Index},{item.Time:HH:mm:ss},{item.Torque:F1},{item.Speed}");
+ }
+ }
+
+ MessageBox.Show($"报表已导出到:{saveDialog.FileName}", "导出成功");
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"导出失败:{ex.Message}", "错误");
+ }
+ }
+
+ public void Clear()
+ {
+ ReportData = new ObservableCollection();
+
+ }
+
+
+ public void ExportToPdfUsingPdfSharp()
+ {
+ try
+ {
+ var saveDialog = new Microsoft.Win32.SaveFileDialog
+ {
+ Filter = "PDF文件|*.pdf",
+ FileName = $"过程报表_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"
+ };
+
+ if (saveDialog.ShowDialog() == true)
+ {
+ // 创建PDF文档
+ PdfDocument document = new PdfDocument();
+ document.Info.Title = "医用刨削器过程测试报表";
+ document.Info.Author = "测试系统";
+ document.Info.CreationDate = DateTime.Now;
+
+ // 添加页面
+ PdfPage page = document.AddPage();
+ XGraphics gfx = XGraphics.FromPdfPage(page);
+
+ // 直接使用系统中文字体名称(Windows系统)
+ // 常见的系统中文字体:
+ // "Microsoft YaHei" - 微软雅黑 (Windows 7+)
+ // "SimSun" - 宋体
+ // "SimHei" - 黑体
+ // "KaiTi" - 楷体
+ string fontName = "Microsoft YaHei"; // 使用微软雅黑
+
+ XFont titleFont = new XFont(fontName, 20, PdfSharpCore.Drawing.XFontStyle.Bold);
+ XFont headerFont = new XFont(fontName, 12, PdfSharpCore.Drawing.XFontStyle.Bold);
+ XFont normalFont = new XFont(fontName, 10, PdfSharpCore.Drawing.XFontStyle.Regular);
+
+ // 页面尺寸
+ double pageWidth = page.Width;
+ double margin = 50;
+ double yPos = margin;
+
+ // 1. 标题
+ gfx.DrawString("医用刨削器过程测试报表", titleFont, XBrushes.Black,
+ new XRect(0, yPos, pageWidth, 30), XStringFormats.TopCenter);
+ yPos += 40;
+
+ // 2. 生成时间
+ gfx.DrawString($"生成时间:{DateTime.Now:yyyy年MM月dd日 HH:mm:ss}", headerFont, XBrushes.Black,
+ new XRect(0, yPos, pageWidth, 20), XStringFormats.TopCenter);
+ yPos += 30;
+
+ // 3. 统计信息
+ string stats = $"数据总数:{DataCount} | 正常:{NormalCount} | 警告:{WarningCount} | 错误:{ErrorCount}";
+ gfx.DrawString(stats, headerFont, XBrushes.DarkBlue,
+ new XRect(margin, yPos, pageWidth - 2 * margin, 20), XStringFormats.TopLeft);
+ yPos += 30;
+
+ // 4. 表格标题
+ gfx.DrawString("测试过程数据明细", headerFont, XBrushes.Black,
+ new XRect(margin, yPos, pageWidth - 2 * margin, 20), XStringFormats.TopLeft);
+ yPos += 25;
+
+ // 5. 绘制表格
+ double columnWidth = (pageWidth - 2 * margin) / 4;
+ double rowHeight = 20;
+
+ // 表头
+ gfx.DrawString("序号", headerFont, XBrushes.Black, margin, yPos);
+ gfx.DrawString("时间", headerFont, XBrushes.Black, margin + columnWidth, yPos);
+ gfx.DrawString("扭矩(N.cm)", headerFont, XBrushes.Black, margin + columnWidth * 2, yPos);
+ gfx.DrawString("转速(rad/min)", headerFont, XBrushes.Black, margin + columnWidth * 3, yPos);
+
+ yPos += rowHeight;
+
+ // 数据行
+ int rowCount = 0;
+ foreach (var item in ReportData)
+ {
+ // 检查是否需要换页
+ if (yPos + rowHeight > page.Height - margin && rowCount > 0)
+ {
+ // 添加新页面
+ page = document.AddPage();
+ gfx = XGraphics.FromPdfPage(page);
+ yPos = margin;
+
+ // 在新页面绘制表头
+ gfx.DrawString("序号", headerFont, XBrushes.Black, margin, yPos);
+ gfx.DrawString("时间", headerFont, XBrushes.Black, margin + columnWidth, yPos);
+ gfx.DrawString("扭矩(N.cm)", headerFont, XBrushes.Black, margin + columnWidth * 2, yPos);
+ gfx.DrawString("转速(rad/min)", headerFont, XBrushes.Black, margin + columnWidth * 3, yPos);
+ yPos += rowHeight;
+ }
+
+ gfx.DrawString(item.Index.ToString(), normalFont, XBrushes.Black, margin, yPos);
+ gfx.DrawString(item.Time.ToString("HH:mm:ss"), normalFont, XBrushes.Black, margin + columnWidth, yPos);
+ gfx.DrawString(item.Torque.ToString("F1"), normalFont, XBrushes.Black, margin + columnWidth * 2, yPos);
+ gfx.DrawString(item.Speed.ToString(), normalFont, XBrushes.Black, margin + columnWidth * 3, yPos);
+
+ yPos += rowHeight;
+ rowCount++;
+ }
+
+ // 保存PDF
+ document.Save(saveDialog.FileName);
+
+ MessageBox.Show($"PDF已导出到:{saveDialog.FileName}", "导出成功");
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"PDF导出失败:{ex.Message}", "错误");
+ }
+ }
+ }
+
+ // 在窗口的代码后台设置DataContext
+ public partial class ProcessReportWindow : Window
+ {
+ public ProcessReportWindow()
+ {
+ InitializeComponent();
+
+ var emergencyWindow = EmergencyStopWindow.Instance;
+ var realData = emergencyWindow?.GetReportData();
+
+ if (realData != null && realData.Count > 0)
+ {
+ // 使用真实数据
+ DataContext = new ReportViewModel(realData);
+ var masx = realData.Select(s => s.Torque).ToList();
+ var lasttime_ = realData.Max(s => s.Time);
+ if (realData.Count > 0)
+ {
+ maxForce.Text = masx.Max().ToString("F3");
+ lasttime.Text = "最后刷新:" + lasttime_.ToString("yyyy-MM-dd HH:mm:ss");
+ }
+
+ }
+ else
+ {
+ // 如果没有真实数据,使用示例数据
+ DataContext = new ReportViewModel();
+ }
+ }
+
+ // 3. 修正单例逻辑:确保单例的 ReportData 可被外部修改,不丢失数据
+ private static ProcessReportWindow _instance;
+ // 加锁保证线程安全
+ private static readonly object _lock = new object();
+ public static ProcessReportWindow Instance
+ {
+ get
+ {
+ lock (_lock)
+ {
+ if (_instance == null || !_instance.IsLoaded)
+ {
+ _instance = new ProcessReportWindow(); // 使用无参构造,初始化空数据
+ }
+ return _instance;
+ }
+ }
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = EmergencyStopWindow.Instance;
+
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ private void Button_Click_1(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ReportViewModel viewModel)
+ {
+ viewModel.ExportData();
+ }
+ }
+
+ private void Button_Click_2(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ReportViewModel viewModel)
+ {
+ viewModel.ExportToPdfUsingPdfSharp();
+ }
+ }
+
+ private void Button_Click_3(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = MainWindow.Instance;
+
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+
+ private void Button_Click_4(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ReportViewModel viewModel)
+ {
+ var emergencyWindow = EmergencyStopWindow.Instance;
+ emergencyWindow?.ClearReportData();
+ viewModel.Clear();
+ }
+
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ReportViewModel viewModel)
+ {
+ viewModel.ExportData();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/TorqueParameterWindow.xaml b/TorqueParameterWindow.xaml
new file mode 100644
index 0000000..d97ab82
--- /dev/null
+++ b/TorqueParameterWindow.xaml
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TorqueParameterWindow.xaml.cs b/TorqueParameterWindow.xaml.cs
new file mode 100644
index 0000000..1ec1150
--- /dev/null
+++ b/TorqueParameterWindow.xaml.cs
@@ -0,0 +1,289 @@
+using Modbus.Device;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using 软胶囊弹性硬度测试仪;
+using 软胶囊弹性硬度测试仪.Data;
+
+
+namespace EmptyLoadTest
+{
+ ///
+ /// Window1.xaml 的交互逻辑
+ ///
+ public partial class TorqueParameterWindow : Window
+ {
+ #region 私有字段
+ private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient;
+ private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
+
+ private readonly DispatcherTimer _readTimer;
+
+ #endregion
+
+ 软胶囊弹性硬度测试仪.Function ma;
+ DataChange c = new DataChange();
+ public TorqueParameterWindow()
+ {
+ InitializeComponent();
+ InitializeModbusTcp();
+ _readTimer = InitDispatcherTimer();
+ }
+
+ private static TorqueParameterWindow _instance;
+ public static TorqueParameterWindow Instance
+ {
+ get
+ {
+ if (_instance == null || !_instance.IsLoaded)
+ {
+ _instance = new TorqueParameterWindow();
+ }
+ return _instance;
+ }
+ }
+
+
+ private void InitializeModbusTcp()
+ {
+ try
+ {
+
+ string plcIp = "192.168.1.10";
+ bool initSuccess = ModbusResourceManager.Instance.Init(plcIp, 502);
+ if (!initSuccess)
+ {
+ MessageBox.Show("连接Modbus服务器失败!", "错误");
+ this.Close();
+ return;
+ }
+
+ // 检查连接状态
+ if (_tcpClient == null || !_tcpClient.Connected)
+ {
+ MessageBox.Show("Modbus连接异常!", "错误");
+ this.Close();
+ return;
+ }
+
+ ma = new Function(_modbusMaster);
+
+ }
+ catch (Exception ex)
+ {
+ ShowError($"Modbus初始化失败: {ex.Message}");
+ }
+ }
+
+ private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+
+
+ private DispatcherTimer InitDispatcherTimer()
+ {
+ var timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(100)
+ };
+ timer.Tick += async (s, e) =>
+ {
+ if (_modbusMaster != null)
+ {
+ try
+ {
+ await ReadAddr262DataAsync();
+ }
+ catch { }
+ }
+ };
+ return timer;
+ }
+
+ private async System.Threading.Tasks.Task ReadAddr262DataAsync()
+ {
+ try
+ {
+ // 创建任务列表
+ var tasks = new List
+ {
+ ReadAndUpdateFloatAsync(1314, 2, force1, "F2", " "),
+ ReadAndUpdateFloatAsync(290, 2, firstspeed, "F2", " "),
+ ReadAndUpdateFloatAsync(500, 2, pressure, "F2", " "),
+ ReadAndUpdateFloatAsync(1360, 2, force2, "F2", " "),
+ ReadAndUpdateFloatAsync(1366, 2, nishizhen, "F2", " "),
+ ReadAndUpdateFloatAsync(1368 ,2, shunshizhen, "F2", " "),
+ ReadAndUpdateFloatAsync(320 ,2, position, "F2", " "),
+ ReadAndUpdateFloatAsync(102 ,2, actualpress, "F2", " "),
+ };
+
+ await Task.WhenAll(tasks);
+ }
+ catch (Exception ex)
+ {
+ ShowError($"读取数据失败:{ex.Message}");
+ }
+ }
+
+ private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBox control, string format, string unit)
+ {
+ try
+ {
+ ushort[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
+ );
+
+ if (registers != null && registers.Length >= 2)
+ {
+ float value = c.UshortToFloat(registers[1], registers[0]);
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ else if (registers != null && registers.Length >= 1)
+ {
+ int value = registers[0];
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
+ }
+ }
+
+ private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBlock control, string format, string unit)
+ {
+ try
+ {
+ ushort[] registers = await Task.Run(async () =>
+ await _modbusMaster?.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
+ );
+
+ if (registers != null && registers.Length >= 2)
+ {
+ float value = c.UshortToFloat(registers[1], registers[0]);
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ else if (registers != null && registers.Length >= 1)
+ {
+ int value = registers[0];
+ Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
+ }
+ }
+
+ private async Task ReadAndUpdateIntAsync(int address, int length, System.Windows.Controls.Control control, string format)
+ {
+ try
+ {
+ ushort[] registers = await Task.Run(() =>
+ _modbusMaster?.ReadHoldingRegisters(1, (ushort)address, (ushort)length)
+ );
+
+ if (registers != null && registers.Length >= 1)
+ {
+ int value = registers[0];
+ Dispatcher.Invoke(() =>
+ {
+ if (control is System.Windows.Controls.ContentControl contentControl)
+ contentControl.Content = value.ToString(format);
+ else if (control is System.Windows.Controls.TextBox textBox)
+ textBox.Text = value.ToString(format);
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
+ }
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ _readTimer?.Start();
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ ma.BtnClickFunctionForNew(Function.ButtonType.复归型, 11);
+ }
+
+ private void force1_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(force1.Text.Trim(), 1314, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void firstspeed_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(firstspeed.Text.Trim(), 290, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void pressure_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(pressure.Text.Trim(), 500, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void force2_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(force2.Text.Trim(), 1360, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void shunshizhen_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(shunshizhen.Text.Trim(), 1368, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void nishizhen_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(nishizhen.Text.Trim(), 1366, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void position_GotFocus(object sender, RoutedEventArgs e)
+ {
+ ma.WriteToPLCForNew(position.Text.Trim(), 320, 软胶囊弹性硬度测试仪.Function.DataType.浮点型);
+ System.Threading.Tasks.Task.Delay(50);
+ t0.Focus();
+ }
+
+ private void Button_Click_1(object sender, RoutedEventArgs e)
+ {
+ var mainWindow = MainWindow.Instance;
+
+ if (!mainWindow.IsVisible)
+ {
+ mainWindow.Show();
+ }
+ else
+ {
+ mainWindow.Activate();
+ }
+
+ Close();
+ }
+ }
+}
diff --git a/医用刨削器特征新版8.csproj b/医用刨削器特征新版8.csproj
new file mode 100644
index 0000000..948ac0d
--- /dev/null
+++ b/医用刨削器特征新版8.csproj
@@ -0,0 +1,28 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/医用刨削器特征新版8.sln b/医用刨削器特征新版8.sln
new file mode 100644
index 0000000..c77d959
--- /dev/null
+++ b/医用刨削器特征新版8.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36327.8 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "医用刨削器特征新版8", "医用刨削器特征新版8.csproj", "{B0C9D63D-2C43-43F4-8273-273BCC58C3AE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B0C9D63D-2C43-43F4-8273-273BCC58C3AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0C9D63D-2C43-43F4-8273-273BCC58C3AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B0C9D63D-2C43-43F4-8273-273BCC58C3AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B0C9D63D-2C43-43F4-8273-273BCC58C3AE}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {AB2E3ED2-3859-47D3-B99F-9DD505925C50}
+ EndGlobalSection
+EndGlobal