C#實現簡單的串口通信


參考網址: https://www.cnblogs.com/ElijahZeng/p/7609241.html

前言     本着學習研究的態度,用c#語言實現簡單的串口通信工具。 一、串口通信原理 串口通信 串口通信(Serial Communications)的概念非常簡單,串口按位(bit)發送和接收字節。盡管比按字節(byte)的並行通信慢,但是串口可以在使用一根線發送數據的同時用另一根線接收數據。它很簡單並且能夠實現遠距離通信。由於串口通信是異步的,端口能夠在一根線上發送數據同時在另一根線上接收數據。其他線用於握手,但不是必須的。串口通信最重要的參數是波特率、數據位、停止位和奇偶校驗。對於兩個進行通信的端口,這些參數必須匹配。 常用術語介紹 波特率:這是一個衡量符號傳輸速率的參數。指的是信號被調制以后在單位時間內的變化,即單位時間內載波參數變化的次數,如每秒鍾傳送240個字符,而每個字符格式包含10位(1個起始位,1個停止位,8個數據位),這時的波特率為240Bd,比特率為10位*240個/秒=2400bps。一般調制速率大於波特率,比如曼徹斯特編碼)。通常電話線的波特率為14400,28800和36600。波特率可以遠遠大於這些值,但是波特率和距離成反比。高波特率常常用於放置的很近的儀器間的通信,典型的例子就是GPIB設備的通信。 數據位:這是衡量通信中實際數據位的參數。當計算機發送一個信息包,實際的數據往往不會是8位的,標准的值是6、7和8位。如何設置取決於你想傳送的信息。比如,標准的ASCII碼是0~127(7位)。擴展的ASCII碼是0~255(8位)。如果數據使用簡單的文本(標准 ASCII碼),那么每個數據包使用7位數據。每個包是指一個字節,包括開始/停止位,數據位和奇偶校驗位。由於實際數據位取決於通信協議的選取,術語"包"指任何通信的情況。 停止位:用於表示單個包的最后一位。典型的值為1,1.5和2位。由於數據是在傳輸線上定時的,並且每一個設備有其自己的時鍾,很可能在通信中兩台設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,並且提供計算機校正時鍾同步的機會。適用於停止位的位數越多,不同時鍾同步的容忍程度越大,但是數據傳輸率同時也越慢。 奇偶校驗位:在串口通信中一種簡單的檢錯方式。有四種檢錯方式:偶、奇、高和低。當然沒有校驗位也是可以的。對於偶和奇校驗的情況,串口會設置校驗位(數據位后面的一位),用一個值確保傳輸的數據有偶個或者奇個邏輯高位。例如,如果數據是011,那么對於偶校驗,校驗位為0,保證邏輯高的位數是偶數個。如果是奇校驗,校驗位為1,這樣就有3個邏輯高位。高位和低位不真正的檢查數據,簡單置位邏輯高或者邏輯低校驗。這樣使得接收設備能夠知道一個位的狀態,有機會判斷是否有噪聲干擾了通信或者是否傳輸和接收數據是否不同步。 串口引腳圖解 1 載波檢測(DCD) 2 接受數據(RXD) 3 發出數據(TXD) 4 數據終端准備好(DTR) 5 信號地線(SG) 6 數據准備好(DSR) 7 請求發送(RTS) 8 清除發送(CTS) 9 振鈴指示(RI)        二、使用System.IO.Port.SerialPort類實現串口通信 System.IO.Port.SerialPort類介紹     System.IO.Port.SerialPort是.NET Framework提供的操作串行端口的類,里面提供了一些方法、屬性和和事件供開發者調用操作串口。 調用流程 1. 直接調用SerialPort的靜態方法GetPortNames()獲取當前計算機的串行端口名稱數組 2.根據串口名稱,初始化SerialPort對象,設置參數,調用Open()方法打開串口 3.調用Write()方法發送數據 4.注冊接收數據的監聽,獲取數據(或者另起線程循環讀取接收數據,本文使用注冊監聽方式接收數據)       具體代碼實現 using System; using System.IO.Ports; using System.Text; namespace PortControlDemo { public class PortControlHelper { #region 字段/屬性/委托 ////// 串行端口對象 ///private SerialPort sp; ////// 串口接收數據委托 ///public delegate void ComReceiveDataHandler(string data); public ComReceiveDataHandler OnComReceiveDataHandler = null; ////// 端口名稱數組 ///public string[] PortNameArr { get; set; } ////// 串口通信開啟狀態 ///public bool PortState { get; set; } = false; ////// 編碼類型 ///public Encoding EncodingType { get; set; } = Encoding.ASCII; #endregion #region 方法 public PortControlHelper() { PortNameArr = SerialPort.GetPortNames(); sp = new SerialPort(); sp.DataReceived += new SerialDataReceivedEventHandler(DataReceived); } ////// 打開端口 ////// 端口名稱 /// 波特率 /// 數據位 /// 停止位 /// 超時時間 public void OpenPort(string portName , int boudRate = 115200, int dataBit = 8, int stopBit = 1, int timeout = 5000) { try { sp.PortName = portName; sp.BaudRate = boudRate; sp.DataBits = dataBit; sp.StopBits = (StopBits)stopBit; sp.ReadTimeout = timeout; sp.Open(); PortState = true; } catch (Exception e) { throw e; } } ////// 關閉端口 ///public void ClosePort() { try { sp.Close(); PortState = false; } catch (Exception e) { throw e; } } ////// 發送數據 ////// public void SendData(string sendData) { try { sp.Encoding = EncodingType; sp.Write(sendData); } catch (Exception e) { throw e; } } ////// 接收數據回調用 ////// /// private void DataReceived(object sender, SerialDataReceivedEventArgs e) { byte[] buffer = new byte[sp.BytesToRead]; sp.Read(buffer, 0, buffer.Length); string str = EncodingType.GetString(buffer); if (OnComReceiveDataHandler != null) { OnComReceiveDataHandler(str); } } #endregion } }   三、編寫Winform串口通信工具界面 界面預覽 操作介紹         本界面主要功能是操作兩個串口,一個發送數據另一個接收數據。左側設置兩串口的一些參數,設置完成后點擊"打開發送接收串口",如兩串口成功打開,右側便可操作發送和接受數據。 具體代碼實現 using System; using System.Windows.Forms; namespace PortControlDemo { public partial class FrmPortControl : Form { #region 字段/屬性 int[] BaudRateArr = new int[] { 110, 300, 1200, 2400, 4800, 115200 }; int[] DataBitArr = new int[] { 6, 7, 8 }; int[] StopBitArr = new int[] { 1, 2, 3}; int[] TimeoutArr = new int[] { 500, 1000, 2000, 5000, 10000 }; object[] CheckBitArr = new object[] { "None"}; private bool ReceiveState = false; private PortControlHelper pchSend; private PortControlHelper pchReceive; #endregion #region 方法 ////// 初始化控件 ///private void InitView() { cb_portNameSend.DataSource = pchSend.PortNameArr; cb_portNameReceive.DataSource = pchReceive.PortNameArr; cb_baudRate.DataSource = BaudRateArr; cb_dataBit.DataSource = DataBitArr; cb_stopBit.DataSource = StopBitArr; cb_checkBit.DataSource = CheckBitArr; cb_timeout.DataSource = TimeoutArr; FreshBtnState(pchSend.PortState && pchReceive.PortState); } ////// 刷新按鈕狀態 ////// private void FreshBtnState(bool state) { if (state) { Btn_open.Text = "關閉發送接收串口"; Btn_send.Enabled = true; Btn_receive.Enabled = true; } else { Btn_open.Text = "打開發送接收串口"; Btn_send.Enabled = false; Btn_receive.Enabled = false; } } #endregion #region 事件 public FrmPortControl() { InitializeComponent(); pchSend = new PortControlHelper(); pchReceive = new PortControlHelper(); InitView(); } ////// 點擊 發送數據 按鈕,發送文本內數據 ////// /// private void Btn_send_Click(object sender, EventArgs e) { pchSend.SendData(tb_send.Text); } ////// 點擊 開始接收 按鈕,開始監聽串口接收入口數據 ////// /// private void Btn_receive_Click(object sender, EventArgs e) { if (ReceiveState) { pchReceive.OnComReceiveDataHandler -= new PortControlHelper.ComReceiveDataHandler(ComReceiveData); Btn_receive.Text = "開始接收"; ReceiveState = false; } else { pchReceive.OnComReceiveDataHandler += new PortControlHelper.ComReceiveDataHandler(ComReceiveData); Btn_receive.Text = "停止接收"; ReceiveState = true; } } ////// 開啟或關閉 兩個通信的串口,刷新按鈕狀態 ////// /// private void Btn_open_Click(object sender, EventArgs e) { if (pchSend.PortState) { pchSend.ClosePort(); pchReceive.ClosePort(); } else { pchSend.OpenPort(cb_portNameSend.Text, int.Parse(cb_baudRate.Text), int.Parse(cb_dataBit.Text), int.Parse(cb_stopBit.Text), int.Parse(cb_timeout.Text)); pchReceive.OpenPort(cb_portNameReceive.Text, int.Parse(cb_baudRate.Text), int.Parse(cb_dataBit.Text), int.Parse(cb_stopBit.Text), int.Parse(cb_timeout.Text)); } FreshBtnState(pchSend.PortState && pchReceive.PortState); pchReceive.OnComReceiveDataHandler += new PortControlHelper.ComReceiveDataHandler(ComReceiveData); Btn_receive.Text = "停止接收"; ReceiveState = true; } ////// 接收到的數據,寫入文本框內 ////// private void ComReceiveData(string data) { this.Invoke(new EventHandler(delegate { tb_receive.AppendText($"接收:{data}\n"); })); } #endregion } }   總結         有框架提供的幫助類,我們實現串口通信雖然不難,但是還是有很多細節要注意的。寫好任何一樣東西都不容易,一起加油吧! 附錄 搭建一個串口調試環境的工具和本文源碼地址,有需要的筒靴自提吧 (ง •̀_•́)ง 串口調試Demo源碼地址:https://files.cnblogs.com/files/ElijahZeng/PortControlDemo.rar 虛擬串口工具vspd:https://files.cnblogs.com/files/ElijahZeng/VSPD%E8%99%9A%E6%8B%9F%E4%B8%B2%E5%8F%A3%E5%B7%A5%E5%85%B7.rar
---------------------
著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
作者:ElijahZeng
源地址:https://www.cnblogs.com/ElijahZeng/p/7609241.html
來源:博客園cnblogs
© 版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM