以下是学习笔记
一,接线图
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())); } } }