Files
pressurediff/压差法气体渗透仪/CoefficientForm.cs

445 lines
16 KiB
C#
Raw Normal View History

2026-02-07 10:07:45 +08:00
using Modbus.Device;
using Sunny.UI;
using Sunny.UI.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using .Data;
namespace
{
public partial class CoefficientForm : UIForm
{
#region
private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient;
private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
private System.Windows.Forms.Timer _readTimer;
#endregion
private TestScreen _testScreen;
Function ma;
DataChange c = new DataChange();
public CoefficientForm()
{
InitializeComponent();
InitTimer();
}
private System.Windows.Forms.Timer InitTimer()
{
var timer = new System.Windows.Forms.Timer()
{
Interval = 1000
};
timer.Tick += async (s, e) =>
{
if (_modbusMaster != null)
{
try
{
await ReadAddr262DataAsync();
}
catch { }
}
};
//timer.Start();
return timer;
}
private async System.Threading.Tasks.Task ReadAddr262DataAsync()
{
try
{
// 添加空值检查
if (_modbusMaster == null || _tcpClient == null || !_tcpClient.Connected)
{
return;
}
// 创建任务列表
var tasks = new List<Task>
{
ReadAndUpdateFloatAsync(1218, 2, uiLabel6,"F2",""),
ReadLeakTestParametersAsync()
//ReadStatusAsync()
};
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
ShowError($"读取数据失败:{ex.Message}");
}
}
private async Task ReadAndUpdateFloatAsync(int address, int length, Label control, string format, string unit)
{
// 空值校验避免传入空控件导致后续Invoke报错
if (control == null)
{
System.Diagnostics.Debug.WriteLine($"读取地址{address}失败目标Label控件为空");
return;
}
try
{
ushort[] registers = await Task.Run(async () =>
{
// 双重空值校验避免_modbusMaster为空导致调用异常
if (_modbusMaster == null) return null;
return await _modbusMaster.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length);
});
// ===================== 数据有效性校验 & 解析 =====================
// 场景1读取到2个及以上寄存器 → 解析为浮点型数据占2个16位寄存器
if (registers != null && registers.Length >= 2)
{
// c.UshortToFloat自定义工具方法将2个16位无符号寄存器转换为32位浮点型
// 参数顺序registers[1]高位寄存器、registers[0](低位寄存器)→ 需匹配设备数据存储格式
float value = c.UshortToFloat(registers[1], registers[0]);
// ===================== WinForm UI控件更新 =====================
// Control.Invoke判断是否跨线程若跨线程则切换到UI线程更新控件
// WinForm中UI控件只能由创建它的主线程修改否则会抛出跨线程异常
if (control.InvokeRequired)
{
control.Invoke(new Action(() =>
{
control.Text = $"{value.ToString(format)}{unit}";
}));
}
else
{
// 若当前已是UI线程直接更新
control.Text = $"{value.ToString(format)}{unit}";
}
}
// 场景2读取到1个寄存器 → 解析为整型数据占1个16位寄存器
else if (registers != null && registers.Length >= 1)
{
// 直接取第一个寄存器的值作为整型数据
int value = registers[0];
// 同样通过Control.Invoke保证UI线程安全更新
if (control.InvokeRequired)
{
control.Invoke(new Action(() =>
{
control.Text = $"{value.ToString(format)}{unit}";
}));
}
else
{
control.Text = $"{value.ToString(format)}{unit}";
}
}
// 场景3registers为null或长度为0 → 无有效数据,不执行更新(静默处理)
else if (registers == null || registers.Length == 0)
{
System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:未获取到有效寄存器数据");
}
}
catch (Exception ex)
{
//System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}\n异常堆栈{ex.StackTrace}");
ShowError($"读取地址{address}失败:{ex.Message}\n异常堆栈{ex.StackTrace}");
}
}
private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
private class RegisterConfig
{
public ushort Address { get; set; } // Modbus寄存器地址ushort类型匹配方法参数
public UITextBox TextBox { get; set; } // 适配SunnyUI的UITextBox控件
public string Format { get; set; } // 数值格式化字符串
public bool IsInteger { get; set; } // 是否为整数类型(新增)
}
private async Task ReadLeakTestParametersAsync()
{
// 前置校验:连接状态检查
if (_tcpClient == null || !_tcpClient.Connected || _modbusMaster == null)
{
return;
}
try
{
// 配置所有寄存器映射关系(统一管理,便于维护)
var registerConfigs = new List<RegisterConfig>
{
CreateRegisterConfig(1018, uiTextBox1, "F3",false), // 高压
CreateRegisterConfig(1118, uiTextBox3, "F3",false), // 低压
CreateRegisterConfig(1222, uiTextBox2, "F3",false), // 温度
CreateRegisterConfig(234, uiTextBox7, "F4",false), // 压降值
CreateRegisterConfig(230, uiTextBox12, "0",true), // 1#平稳系数
CreateRegisterConfig(242, uiTextBox9, "F2",false), // CM3 GTR系数
CreateRegisterConfig(246, uiTextBox10, "F2",false), // CM3 GT系数
CreateRegisterConfig(252, uiTextBox11, "F2",false), // mol GTR系数
CreateRegisterConfig(256, uiTextBox5, "F2",false) // mol GT系数
};
// 批量处理所有寄存器读取和UI更新
foreach (var config in registerConfigs)
{
await ReadRegisterAndUpdateUIAsync(config);
}
}
catch (Exception ex)
{
this.Invoke(new Action(() =>
{
UIMessageBox.ShowError($"读取系数失败:{ex.Message}");
}));
}
}
/// <summary>
/// 辅助方法创建寄存器配置对象适配C# 7.3语法)
/// </summary>
/// <param name="address">寄存器地址</param>
/// <param name="textBox">绑定的SunnyUI文本框</param>
/// <param name="format">数值格式化字符串</param>
private RegisterConfig CreateRegisterConfig(int address, UITextBox textBox, string format, bool isInteger)
{
var config = new RegisterConfig();
config.Address = (ushort)address; // 显式转换为ushort解决类型不匹配
config.TextBox = textBox;
config.Format = format;
config.IsInteger = isInteger; // 赋值整数类型标识
return config;
}
/// <summary>
/// 通用方法读取寄存器并更新SunnyUI文本框核心逻辑复用
/// </summary>
/// <param name="config">寄存器配置</param>
private async Task ReadRegisterAndUpdateUIAsync(RegisterConfig config)
{
// 异步读取Modbus寄存器避免阻塞UI线程
ushort[] registers = await Task.Run(() =>
_modbusMaster?.ReadHoldingRegisters(1, config.Address, 2));
// 数据有效性校验 + 区分整数/浮点处理
if (registers != null && registers.Length >= 2)
{
this.Invoke(new Action(() =>
{
if (config.IsInteger)
{
// 整数处理合并两个ushort为32位整数根据Modbus字节序调整
// 注意字节序需匹配设备端此处为registers[1]高位 + registers[0]低位)
int intValue = (registers[1] << 16) | registers[0];
config.TextBox.Text = intValue.ToString(config.Format);
}
else
{
// 浮点处理:保持原有逻辑
float floatValue = c.UshortToFloat(registers[1], registers[0]);
config.TextBox.Text = floatValue.ToString(config.Format);
}
}));
}
}
private void ShowErrorMsg(string msg)
{
// 判断当前线程是否是UI线程避免跨线程访问控件异常
if (this.InvokeRequired)
{
// 跨线程时通过Invoke切换到UI线程执行
this.Invoke(new Action<string>(ShowErrorMsg), msg);
return;
}
// UI线程直接显示错误提示框
MessageBox.Show(msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//返回
private void uiButton1_Click(object sender, EventArgs e)
{
SwitchWindow(ref _testScreen, () => new TestScreen());
}
private void CoefficientForm_Load(object sender, EventArgs e)
{
string plcIp = "192.168.1.10";
bool initSuccess = Data.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);
_readTimer = InitTimer();
// 等_modbusMaster初始化完成后手动启动
if (_modbusMaster != null)
{
_readTimer.Start();
}
}
private void SwitchWindow<T>(ref T windowInstance, Func<T> createFunc) where T : UIForm
{
//1.停止当前窗口的定时器(不释放资源)
_readTimer?.Stop();
// 2. 检查资源是否可用(添加重连机制)
if (_tcpClient == null || !_tcpClient.Connected || _modbusMaster == null)
{
//尝试重新连接
bool reconnectSuccess = TryReconnect();
if (!reconnectSuccess)
{
MessageBox.Show("TCP连接已断开请重新连接", "提示");
return;
}
}
// 3. 复用窗口实例:不存在则创建,存在则激活
if (windowInstance == null)
{
windowInstance = createFunc();
// 添加窗口关闭事件处理
windowInstance.Closed += (s, args) =>
{
// 窗口关闭时重新启动定时器并显示当前窗口
//_readtimer?.Start();
//this.Show();
this.Activate();
};
}
else
{
// 激活已存在的窗口(前置显示)
windowInstance.Activate();
return;
}
// 4. 切换窗口:隐藏当前窗口,显示目标窗口(非模态)
this.Hide();
windowInstance.Show(); // 使用 Show() 而不是 ShowDialog()
}
private bool TryReconnect()
{
try
{
string plcIp = "192.168.1.10";
bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502);
if (initSuccess)
{
ma = new Function(_modbusMaster);
return true;
}
}
catch (Exception ex)
{
ShowError($"重新连接失败:{ex.Message}");
}
return false;
}
private void uiTextBox1_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox1.Text.Trim(), 1018, Function.DataType., 3);//高压
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox3_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox3.Text.Trim(), 1118, Function.DataType., 3);//低压
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox2_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox2.Text.Trim(), 1222, Function.DataType., 3);//温度
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox7_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox7.Text.Trim(), 234, Function.DataType., 4);//自身压降值
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox12_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox12.Text.Trim(), 230, Function.DataType.);//1#平稳系数
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox9_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox9.Text.Trim(), 242, Function.DataType.);//CM3 GTR系数
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox10_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox10.Text.Trim(), 246, Function.DataType.);//CM3 GT系数
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox11_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox11.Text.Trim(), 252, Function.DataType.);//mol GTR系数
System.Threading.Tasks.Task.Delay(50);
}
private void uiTextBox5_Click(object sender, EventArgs e)
{
ma?.WriteToPLCForNew(uiTextBox5.Text.Trim(), 256, Function.DataType.);//mol GT系数
System.Threading.Tasks.Task.Delay(50);
}
private void CoefficientForm_FormClosing(object sender, FormClosingEventArgs e)
{
_readTimer?.Stop();
_readTimer?.Dispose();
// 仅用户主动关闭时退出应用
if (e.CloseReason == CloseReason.UserClosing)
{
ModbusResourceManager.Instance?.Dispose();
Application.Exit();
}
}
}
}