C#--Modbus-一主多从-委托跨线程更新UI界面
以下是学习笔记
一,接线图
3台仪表设备接在一起

二,界面设计:

三,代码实现:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DAL;
namespace ModbusDemo
{
//委托跨线程更新UI步骤【1】:声明一个delegate委托类型:UpdateDelegate。
delegate void UpdateDelegate();
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
this.Load += FrmMain_Load;
}
//委托跨线程更新UI步骤【2】:创建一个UpdateDelegate类型的对象。
UpdateDelegate updateGUI;
Modbus objMod = new Modbus();
bool CommOK = false;
bool ReadEnable = true;
Dictionary<int, byte[]> CommValue = new Dictionary<int, byte[]>();
Dictionary<int, List<string>> CurrentValue = new Dictionary<int, List<string>>();
private void FrmMain_Load(object sender, EventArgs e)
{
//委托跨线程更新UI步骤【3】:给updateGUI(委托)对象绑定一个方法。
updateGUI = UpdateUI;
for (int i = 0; i < 5; i++)
{
this.cmb_1stNum.Items.Add(i.ToString());
this.cmb_2ndNum.Items.Add(i.ToString());
this.cmb_3rdNum.Items.Add(i.ToString());
}
if (objMod.OpenMyComm(9600, "COM3", 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One))
{
CommOK = true;
}
else
{
MessageBox.Show("串口打开失败,请检查串口!", "串口打开 ");
return;
}
Thread t = new Thread(new ThreadStart(Comm));
t.IsBackground = true;
t.Start();
}
/// <summary>
/// 线程执行的方法
/// </summary>
private void Comm()
{
while (CommOK)
{
//第一步:数据读取
//对于从站1,读取0-4共5个寄存器
CommValue[1] = objMod.ReadKeepReg(1, 0, 5);
//对于从站2和从站3,读取0-3共4个寄存器
CommValue[2] = objMod.ReadKeepReg(2, 0, 4);
CommValue[3] = objMod.ReadKeepReg(3, 0, 4);
//第二步:数据解析
AnalyseData();
//第三步:更新到界面
//委托跨线程更新UI步骤【6】:在线程中调用委托。
updateGUI();
}
}
/// <summary>
/// 数据解析
/// </summary>
private void AnalyseData()
{
byte[] res;
List<string> list;
foreach (int item in CommValue.Keys)
{
switch (item)
{
//从站1
case 1:
res = CommValue[1];
list = new List<string>();
if (res != null && res.Length == 10)
{
//计数值
Int32 res1 = ByteArrayToInt32(new byte[4] { res[0], res[1], res[2], res[3] });
list.Add(res1.ToString());
Int16 res2 = ByteArrayToInt16(new byte[2] { res[6], res[7] });
list.Add(res2.ToString());
}
CurrentValue[1] = list;
break;
case 2:
res = CommValue[2];
list = new List<string>();
if (res != null && res.Length == 8)
{
//计时值
Int32 res1 = ByteArrayToInt32(new byte[4] { res[0], res[1], res[2], res[3] });
list.Add(res1.ToString());
Int16 res2 = ByteArrayToInt16(new byte[2] { res[6], res[7] });
list.Add(res2.ToString());
}
CurrentValue[2] = list;
break;
case 3:
res = CommValue[3];
list = new List<string>();
if (res != null && res.Length == 8)
{
//计时值
Int32 res1 = ByteArrayToInt32(new byte[4] { res[0], res[1], res[2], res[3] });
list.Add(res1.ToString());
Int16 res2 = ByteArrayToInt16(new byte[2] { res[6], res[7] });
list.Add(res2.ToString());
}
CurrentValue[3] = list;
break;
}
}
}
/// <summary>
/// 委托跨线程更新UI步骤【4】:更新UI的方法。
/// </summary>
private void UpdateUI()
{
if (CurrentValue.Count == 3)
{
//判断该方法是否被主线程调用,也就是创建窗体控件的线程,当控件的InvokeRequired属性为ture时,说明是被主线程以外的线程调用。如果不加判断,会造成异常
if (this.InvokeRequired)//判断
{
//委托跨线程更新UI步骤【5】:激活委托。
this.Invoke(updateGUI);
}
else
{
if (CurrentValue[1].Count>0)
{
this.txt_1stNum.Text = CurrentValue[1][0];
this.cmb_1stNum.Text = CurrentValue[1][1];
}
if (CurrentValue[2].Count > 0)
{
this.txt_2ndNum.Text = CurrentValue[2][0];
this.cmb_2ndNum.Text = CurrentValue[2][1];
}
if (CurrentValue[3].Count > 0)
{
this.txt_3rdNum.Text = CurrentValue[3][0];
this.cmb_3rdNum.Text = CurrentValue[3][1];
}
}
}
}
/// <summary>
/// 4个字节转换成一个长整形
/// </summary>
/// <param name="byteArray"></param>
/// <returns></returns>
private Int32 ByteArrayToInt32(byte[] byteArray)
{
if (byteArray.Length == 4)
{
return (Int32)(byteArray[3] + byteArray[2] * Math.Pow(2, 8) + byteArray[1] * Math.Pow(2, 16) + byteArray[0] * Math.Pow(2, 24));
}
else
{
return 0;
}
}
private Int16 ByteArrayToInt16(byte[] byteArray)
{
if (byteArray.Length == 2)
{
return (Int16)(byteArray[1] + byteArray[0] * Math.Pow(2, 8));
}
else
{
return 0;
}
}
private void btn_Set1_Click(object sender, EventArgs e)
{
objMod.PreSetKeepReg(1, 3, int.Parse(this.txt_Set1.Text.Trim()));
}
private void btn_Set2_Click(object sender, EventArgs e)
{
objMod.PreSetKeepReg(2, 3, int.Parse(this.txt_Set2.Text.Trim()));
}
private void btn_Set3_Click(object sender, EventArgs e)
{
objMod.PreSetKeepReg(3, 3, int.Parse(this.txt_Set3.Text.Trim()));
}
}
}

浙公网安备 33010602011771号