C#中Form1连接Modbus后 如何让Form2调用FC01/FC03等Modbus功能
解决方法
问题根源
你当前无法在Form2调用Modbus功能是两个核心原因导致的:
- Form2中每次触发打开通信窗体的操作时,都会new一个新的
frCommunication实例,之前已经完成串口连接、隐藏起来的旧实例无法被访问,新实例的串口处于未连接状态 frCommunication中的ModbusMaster实例、串口状态都是私有成员,Form2没有访问权限
具体修改步骤
第一步:修改frCommunication(Form1)代码
公开必要的状态和封装Modbus操作方法,避免直接暴露内部实现:
namespace ATS { public partial class frCommunication : Form { SerialPort serialPort = new SerialPort(); ModbusMaster Master; // 你的原有委托、其他代码保持不变 // 新增:公开串口连接状态 public bool IsSerialConnected => serialPort != null && serialPort.IsOpen && Master != null; // 新增:封装FC01 写单线圈方法 public void WriteSingleCoil(byte slaveId, ushort coilAddr, bool value) { if (!IsSerialConnected) throw new InvalidOperationException("串口未连接或Modbus主站未初始化"); Master.WriteSingleCoil(slaveId, coilAddr, value); } // 新增:封装FC03 读保持寄存器方法 public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddr, ushort length) { if (!IsSerialConnected) throw new InvalidOperationException("串口未连接或Modbus主站未初始化"); return Master.ReadHoldingRegisters(slaveId, startAddr, length); } // 新增:封装FC04 读输入寄存器方法,其他功能码按同样逻辑添加即可 public ushort[] ReadInputRegisters(byte slaveId, ushort startAddr, ushort length) { if (!IsSerialConnected) throw new InvalidOperationException("串口未连接或Modbus主站未初始化"); return Master.ReadInputRegisters(slaveId, startAddr, length); } // 新增:公共断开连接方法,供外部调用 public void CloseSerial() { if (serialPort.IsOpen) { serialPort.Close(); btnConnect.Enabled = true; btnDisconnect.Enabled = false; lblDisplay.Text = "Disconnected"; lblDisplay.ForeColor = Color.Green; } } // 你的原有其他代码保持不变 } }
第二步:修改frMain(Form2)代码
将frCommunication改为全局成员,避免重复创建新实例:
namespace ATS { public partial class frMain : Form { // 新增:全局保存通信窗体实例,避免重复创建 private frCommunication _commForm; public frMain() { InitializeComponent(); } // 修改连接按钮逻辑,复用同一个通信窗体实例 private void btnConnect_Click(object sender, EventArgs e) { if (_commForm == null || _commForm.IsDisposed) { _commForm = new frCommunication(); // 绑定数据传输委托 _commForm.truyendata = LoadData; _commForm.truyendata1 = LoadData1; _commForm.truyendata2 = LoadData2; } _commForm.ShowDialog(); } // 修改打开Grid按钮逻辑,直接调用通信窗体封装好的Modbus方法 private void btnOn_Grid_Click(object sender, EventArgs e) { try { if (_commForm != null && _commForm.IsSerialConnected) { // 示例:写1号从站0地址线圈为true _commForm.WriteSingleCoil(1, 0, true); MessageBox.Show("操作成功"); } else { MessageBox.Show("请先完成Modbus串口连接"); } } catch (Exception ex) { MessageBox.Show($"操作失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // 新增:主窗体关闭时主动断开串口,避免资源泄漏 private void frMain_FormClosing(object sender, FormClosingEventArgs e) { if (_commForm != null && !_commForm.IsDisposed) { _commForm.CloseSerial(); _commForm.Close(); } } // 你的原有其他代码保持不变 } }
修改完成后记得给frMain的FormClosing事件绑定上面新增的frMain_FormClosing方法。
注意事项
- 如果有高频Modbus读写操作,不要直接在UI线程执行,建议用
Task.Run放到后台线程执行,更新UI时再通过Control.Invoke切换回UI线程,避免窗体卡顿 - Modbus操作建议统一加异常捕获,避免串口异常导致程序崩溃
内容的提问来源于stack exchange,提问作者tutjbs
相关产品推荐
相关产品推荐

