您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關利用C# 項目實現一個串口監視上位機功能,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
實現上位機和下位機之間的通信,通常使用的是串口通信,接下來實現一個通過上位機和串口調試助手來完成串口通信測試。
首先創建一個WInfrom窗體應用工程文件,在創建好的工程下面,通過工具箱中已有的控件完成界面的搭建,如下圖所示,為了方便初學者容易看懂程序,下圖將控件的命名一并標注出來:
直接進入正題,將完整的工程代碼黏貼出來:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; using System.Diagnostics; namespace Tem_Hum_Monitorring { public partial class Form1 : Form { //實例化串口 SerialPort s = new SerialPort(); public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; button1.Text = "打開串口"; int[] item = { 9600,115200}; //遍歷 foreach (int a in item) { comboBox2.Items.Add(a.ToString()); } comboBox2.SelectedItem = comboBox2.Items[1]; } private void Form1_Load(object sender, EventArgs e) { portInit(); } /// <summary> /// 串口初始化 /// </summary> private void portInit() { string[] ports = SerialPort.GetPortNames(); comboBox1.Items.AddRange(ports); comboBox1.SelectedItem = comboBox1.Items[0]; } #region 開關串口 private void button1_Click(object sender, EventArgs e) { try { if (!s.IsOpen) { s.PortName = comboBox1.SelectedItem.ToString(); s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString()); s.Open(); s.DataReceived += s_DataReceived; //"+="代表指定響應事件時要調用的方法 button1.Text = "關閉串口"; } else { s.Close(); s.DataReceived -= s_DataReceived; button1.Text = "打開串口"; } } catch(Exception ee) { MessageBox.Show(ee.ToString()); } } #endregion #region 串口接收 void s_DataReceived(object sender, SerialDataReceivedEventArgs e) { int count = s.BytesToRead; string str = null; if (count == 8) { //數據解析 byte[] buff = new byte[count]; s.Read(buff, 0, count); foreach (byte item in buff) { str += item.ToString("X2") + " "; } richTextBox1.Text = "[" + System.DateTime.Now.ToString() + "] " + str + "\n" + richTextBox1.Text; if (buff[0] == 0x04) { ID.Text = buff[0].ToString(); switch (buff[2]) { case 0x01: { Tem.Text = (buff[5] * 4 + buff[4] * 0.05 - 30).ToString(); Hum.Text = (buff[6] + buff[7]).ToString(); break; } case 0x02: { Light.Text = (buff[6] + buff[7]).ToString(); break; } case 0x04: { Dust.Text = (buff[6] + buff[7]).ToString(); break; } default: break; } } } else { //當接收數據不在設定的數據位范圍之內時,會出現接受到的數據一直保存在接收緩存區之內,后續每次接手數據都會將上一次的數據進行疊加,造成只能通過關閉串口的方法來清除緩沖區的數據 s.DiscardInBuffer(); //丟棄來自串行驅動程序的接收緩沖區的數據 } } #endregion #region 串口發送 private void button3_Click(object sender, EventArgs e) { string[] sendbuff = richTextBox2.Text.Split(); Debug.WriteLine("發送字節數:" + sendbuff.Length); foreach (string item in sendbuff) { int count = 1; byte[] buff = new byte[count]; buff[0] = byte.Parse(item, System.Globalization.NumberStyles.HexNumber); s.Write(buff,0,count); } } #endregion private void button2_Click(object sender, EventArgs e) { int count = 1; byte[] buff = new byte[count]; buff[0] = byte.Parse("04", System.Globalization.NumberStyles.HexNumber); s.Write(buff, 0, count); } } }
在Winfrom窗體設計中,實現串口可以通過工具箱中的串口控件來實現,不過一般推薦直接通過代碼來實例化串口,實例化串口需使用如下代碼來實現:
//實例化串口 SerialPort s = new SerialPort();
串口初始化可以在窗體的Load函數中實現,以下初始化可以自動化取當前設備中的存在的串口,包括真實串口和虛擬串口:
private void Form1_Load(object sender, EventArgs e) { portInit(); } /// <summary> /// 串口初始化 /// </summary> private void portInit() { string[] ports = SerialPort.GetPortNames(); comboBox1.Items.AddRange(ports); comboBox1.SelectedItem = comboBox1.Items[0]; }
通過對開關按鍵button1控件的點擊事件,實現串口的開關,通過對控件的文字修改,可以實現一個控件機能實現開又能實現關串口的作用:
#region 開關串口 private void button1_Click(object sender, EventArgs e) { try { if (!s.IsOpen) { s.PortName = comboBox1.SelectedItem.ToString(); s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString()); s.Open(); s.DataReceived += s_DataReceived; //"+="代表指定響應事件時要調用的方法 button1.Text = "關閉串口"; } else { s.Close(); s.DataReceived -= s_DataReceived; button1.Text = "打開串口"; } } catch(Exception ee) { MessageBox.Show(ee.ToString()); } } #endregion
串口數據接收和數據解析,首先獲取數據接收緩存區數據的字節長度,通過確認長度是否是設定中的長度大小,如果是設定的8位數據長度則對接收的數據進行解析:
#region 串口接收 void s_DataReceived(object sender, SerialDataReceivedEventArgs e) { int count = s.BytesToRead; string str = null; if (count == 8) { //數據解析 byte[] buff = new byte[count]; s.Read(buff, 0, count); foreach (byte item in buff) { str += item.ToString("X2") + " "; } richTextBox1.Text = "[" + System.DateTime.Now.ToString() + "] " + str + "\n" + richTextBox1.Text; if (buff[0] == 0x04) { ID.Text = buff[0].ToString(); switch (buff[2]) { case 0x01: { Tem.Text = (buff[5] * 4 + buff[4] * 0.05 - 30).ToString(); Hum.Text = (buff[6] + buff[7]).ToString(); break; } case 0x02: { Light.Text = (buff[6] + buff[7]).ToString(); break; } case 0x04: { Dust.Text = (buff[6] + buff[7]).ToString(); break; } default: break; } } } else { //當接收數據不在設定的數據位范圍之內時,會出現接受到的數據一直保存在接收緩存區之內,后續每次接手數據都會將上一次的數據進行疊加,造成只能通過關閉串口的方法來清除緩沖區的數據 s.DiscardInBuffer(); //丟棄來自串行驅動程序的接收緩沖區的數據 } } #endregion
當接收到的數據長度不等于8的時候,將丟棄來自串行驅動程序的接收緩沖區的數據,接下來通過斷點調試來分析丟棄緩沖區和不丟棄緩沖區數據兩種情況進行仿真,分析如下幾點。
使用串口助手給上位機發送數據數據位長度為8位的數據,串口調試助手和上位機的終端的顯示界面如下,發送端數據和接收端數據一樣,并未出現異常:
將串口調試助手發送數據位修改成9位之后,進行發送,可以發現上位機并未接收到相關的數據:
接著修改串口調試助手的發送數據位,修改成8位,可以發現上位機尚未能接收到來自串口調試助手發來的數據,這是為什么呢?
接下來將通過斷點逐步進行調試,來解釋是為啥上位機沒有接收到調試助手發來的數據,當串口調試助手發來的數據長度位9位時,通過監視器可以查看到接收緩沖器中的數據長度長度是9
第一次點擊完發送之后,上位機未能成功接收到數據,我們就會好奇,并且一般都會點擊第二次、第三次、甚至一直點下去,觀察是否會出現啥異常現象,當點擊第二次時,通過監視窗口,可以觀察到到串口緩沖區的數據長度變成了18,這是因為緩沖區將上一次接收的數據給保留了下來并沒有刪除,就算下次發送的數據長度為8位的時候,也一樣是通過疊加的方式將其保存到緩沖區,這樣就會造成緩沖區的數據位長度會一直大于8;如果不通過s.DiscardInBuffer()方法丟棄來自串行驅動程序的接收緩沖區的數據,就只能通過關閉串口然后重新打開相應的串口來實現緩沖區的數據清除。
使用s.DiscardInBuffer()對不符合長度的數據進行丟棄,實現的效果如下所示:
關于利用C# 項目實現一個串口監視上位機功能就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。