diff --git a/MainWindow.xaml b/MainWindow.xaml
index af6d933..a1a6dad 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -73,18 +73,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 6785a86..12f8057 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -3,7 +3,9 @@ using PetroleumViscosityTest.Controls;
using PetroleumViscosityTest.Models;
using System;
using System.Collections.Generic;
+using System.IO.Ports;
using System.Linq;
+using System.Timers;
using System.Windows;
using System.Windows.Controls;
@@ -13,6 +15,18 @@ namespace PetroleumViscosityTest
{
private ViscosityTestData currentData;
private List rawTimes = new List();
+ // --- 新增 Modbus 通信相关字段 ---
+ private SerialPort serialPort;
+ private System.Timers.Timer readTimer;
+ private byte slaveId = 0x01; // 从机地址,根据实际修改
+ private readonly object portLock = new object();
+
+
+ private System.Diagnostics.Stopwatch stopwatch1 = new System.Diagnostics.Stopwatch();
+ private System.Diagnostics.Stopwatch stopwatch2 = new System.Diagnostics.Stopwatch();
+ private System.Diagnostics.Stopwatch stopwatch3 = new System.Diagnostics.Stopwatch();
+ private System.Diagnostics.Stopwatch stopwatch4 = new System.Diagnostics.Stopwatch();
+ // --------------------------------
public MainWindow()
{
@@ -20,7 +34,218 @@ namespace PetroleumViscosityTest
currentData = new ViscosityTestData();
dpTestDate.SelectedDate = DateTime.Today;
UpdateThermostatTime();
+
+ // --- 新增:初始化串口通信 ---
+ InitSerialPort();
+ // --------------------------------
}
+
+ private void InitSerialPort()
+ {
+ try
+ {
+ serialPort = new SerialPort("COM6", 9600, Parity.None, 8, StopBits.One); // 请根据实际COM口修改
+ serialPort.DataReceived += SerialPort_DataReceived;
+ serialPort.Open();
+
+ // 启动定时器,每隔 5 秒读取一次
+ readTimer = new System.Timers.Timer(2000);
+ readTimer.Elapsed += ReadTimer_Elapsed;
+ readTimer.AutoReset = true;
+ readTimer.Start();
+
+ txtStatus.Text = "串口已打开,正在读取数据...";
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"串口打开失败: {ex.Message}\n请检查COM口号及连接。", "通信错误", MessageBoxButton.OK, MessageBoxImage.Warning);
+ txtStatus.Text = "串口打开失败";
+ }
+ }
+
+ //private void ReadTimer_Elapsed(object sender, ElapsedEventArgs e)
+ //{
+ // // 发送读保持寄存器指令:功能码 0x03,起始地址 0x0005,读取 2 个寄存器
+ // byte[] request = new byte[8];
+ // request[0] = slaveId;
+ // request[1] = 0x03; // 功能码
+ // request[2] = 0x00; // 起始地址高字节
+ // request[3] = 0x05; // 起始地址低字节 (0x0005)
+ // request[4] = 0x00; // 数量高字节
+ // request[5] = 0x02; // 数量低字节 (2 个寄存器)
+ // byte[] crc = CalculateCRC16(request, 6);
+ // request[6] = crc[0];
+ // request[7] = crc[1];
+
+ // lock (portLock)
+ // {
+ // if (serialPort != null && serialPort.IsOpen)
+ // {
+ // try
+ // {
+ // serialPort.Write(request, 0, request.Length);
+ // }
+ // catch (Exception ex)
+ // {
+ // Dispatcher.Invoke(() => txtStatus.Text = $"发送失败: {ex.Message}");
+ // }
+ // }
+ // }
+ //}
+ // 替换原有的 ReadTimer_Elapsed 方法
+ private void ReadTimer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ lock (portLock)
+ {
+ if (serialPort == null || !serialPort.IsOpen) return;
+
+ // 从 0x0000 开始读取 20 个寄存器
+ byte[] request = new byte[8];
+ request[0] = slaveId;
+ request[1] = 0x03;
+ request[2] = 0x00;
+ request[3] = 0x00; // 起始地址 0x0000
+ request[4] = 0x00;
+ request[5] = 0x14; // 读取 20 个寄存器 (0x0000 ~ 0x0013)
+ byte[] crc = CalculateCRC16(request, 6);
+ request[6] = crc[0];
+ request[7] = crc[1];
+
+ try
+ {
+ serialPort.Write(request, 0, request.Length);
+ }
+ catch { }
+ }
+ }
+
+ private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
+ {
+ try
+ {
+ System.Threading.Thread.Sleep(50);
+ byte[] buffer = new byte[serialPort.BytesToRead];
+ serialPort.Read(buffer, 0, buffer.Length);
+
+ if (buffer.Length < 9 || buffer[0] != slaveId || buffer[1] != 0x03)
+ return;
+
+ // 解析温度 (0x0005)
+ int tempIndex = 3 + (0x0005 - 0x0000) * 2;
+ ushort rawTemp = (ushort)((buffer[tempIndex] << 8) | buffer[tempIndex + 1]);
+ double temp = rawTemp / 100.0;
+
+ // 解析运行时间 (0x0007) - 这才是您要的恒温时间!
+ int timeIndex = 3 + (0x0007 - 0x0000) * 2;
+ ushort rawRunTime = (ushort)((buffer[timeIndex] << 8) | buffer[timeIndex + 1]);
+
+ // 根据 0x000F 的值判断单位(0=分钟,1=小时)
+ int unitIndex = 3 + (0x000F - 0x0000) * 2;
+ ushort timeUnit = (ushort)((buffer[unitIndex] << 8) | buffer[unitIndex + 1]);
+
+ int displayTime = rawRunTime;
+ string unit = "分钟";
+ if (timeUnit == 1)
+ {
+ displayTime = rawRunTime; // 小时
+ unit = "小时";
+ }
+
+ Dispatcher.Invoke(() =>
+ {
+ txtTestTemp.Text = temp.ToString("F2");
+
+ // 只有当运行时间 >0 时才显示,否则显示等待状态
+ if (rawRunTime > 0)
+ {
+ txtThermostatTime.Text = displayTime.ToString();
+ txtStatus.Text = $"温度: {temp:F2}℃ 已运行: {displayTime} {unit} 时间单位寄存器: {timeUnit}";
+ }
+ else
+ {
+ txtThermostatTime.Text = "0";
+ txtStatus.Text = $"温度: {temp:F2}℃ 等待启动... (运行时间=0)";
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ Dispatcher.Invoke(() => txtStatus.Text = $"接收错误: {ex.Message}");
+ }
+ }
+
+ //private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
+ //{
+ // try
+ // {
+ // System.Threading.Thread.Sleep(50); // 等待数据收完
+ // byte[] buffer = new byte[serialPort.BytesToRead];
+ // serialPort.Read(buffer, 0, buffer.Length);
+
+ // // 最小有效响应长度:地址(1) + 功能码(1) + 字节数(1) + 数据(2*2) + CRC(2) = 9
+ // if (buffer.Length < 9 || buffer[0] != slaveId || buffer[1] != 0x03)
+ // return;
+
+ // // 提取数据:温度寄存器 (0x0005) 和 运行时间寄存器 (0x0007)
+ // ushort rawTemp = (ushort)((buffer[3] << 8) | buffer[4]);
+ // ushort rawRunTime = (ushort)((buffer[5] << 8) | buffer[6]);
+
+ // double temp = rawTemp / 100.0; // 协议规定小数点2位
+ // int runTimeMinutes = rawRunTime; // 假设单位是分钟,直接显示
+
+ // // 更新 UI
+ // Dispatcher.Invoke(() =>
+ // {
+ // // 更新试验温度(如果希望保留手动输入能力,可添加判断条件,这里直接覆盖)
+ // txtTestTemp.Text = temp.ToString("F2");
+
+ // // 更新恒温时间
+ // txtThermostatTime.Text = runTimeMinutes.ToString();
+
+ // txtStatus.Text = $"实时温度: {temp:F2}℃ 运行时间: {runTimeMinutes} min";
+ // });
+ // }
+ // catch (Exception ex)
+ // {
+ // Dispatcher.Invoke(() => txtStatus.Text = $"接收错误: {ex.Message}");
+ // }
+ //}
+
+
+ private byte[] CalculateCRC16(byte[] data, int length)
+ {
+ ushort crc = 0xFFFF;
+ for (int pos = 0; pos < length; pos++)
+ {
+ crc ^= data[pos];
+ for (int i = 8; i != 0; i--)
+ {
+ if ((crc & 0x0001) != 0)
+ {
+ crc >>= 1;
+ crc ^= 0xA001;
+ }
+ else
+ {
+ crc >>= 1;
+ }
+ }
+ }
+ return new byte[] { (byte)(crc & 0xFF), (byte)(crc >> 8) };
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+ readTimer?.Stop();
+ readTimer?.Dispose();
+ if (serialPort != null && serialPort.IsOpen)
+ {
+ serialPort.Close();
+ serialPort.Dispose();
+ }
+ }
+
// 温度变化时自动更新恒温时间(表2)
private void TxtTestTemp_TextChanged(object sender, TextChangedEventArgs e)
@@ -310,5 +535,57 @@ namespace PetroleumViscosityTest
}
}
}
+
+ // 第1次
+ private void BtnStart1_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch1.Reset();
+ stopwatch1.Start();
+ }
+
+ private void BtnStop1_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch1.Stop();
+ txtTime1.Text = (stopwatch1.Elapsed.TotalSeconds).ToString("F3");
+ }
+
+ // 第2次
+ private void BtnStart2_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch2.Reset();
+ stopwatch2.Start();
+ }
+
+ private void BtnStop2_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch2.Stop();
+ txtTime2.Text = (stopwatch2.Elapsed.TotalSeconds).ToString("F3");
+ }
+
+ // 第3次
+ private void BtnStart3_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch3.Reset();
+ stopwatch3.Start();
+ }
+
+ private void BtnStop3_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch3.Stop();
+ txtTime3.Text = (stopwatch3.Elapsed.TotalSeconds).ToString("F3");
+ }
+
+ // 第4次
+ private void BtnStart4_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch4.Reset();
+ stopwatch4.Start();
+ }
+
+ private void BtnStop4_Click(object sender, RoutedEventArgs e)
+ {
+ stopwatch4.Stop();
+ txtTime4.Text = (stopwatch4.Elapsed.TotalSeconds).ToString("F3");
+ }
}
}
\ No newline at end of file
diff --git a/PetroleumViscosityTest.csproj b/PetroleumViscosityTest.csproj
index 6e6420e..badb9a1 100644
--- a/PetroleumViscosityTest.csproj
+++ b/PetroleumViscosityTest.csproj
@@ -8,4 +8,8 @@
true
+
+
+
+