串口通信原理
串口通信(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)

c#實現串口通信
使用System.IO.Port.SerialPort類實現串口通信
System.IO.Port.SerialPort類介紹
System.IO.Port.SerialPort是.NET Framework提供的操作串行端口的類,里面提供了一些方法、屬性和和事件供開發者調用操作串口。
串口端口號搜索
string[] portList = System.IO.Ports.SerialPort.GetPortNames(); for (int i = 0; i < portList.Length; i++) { string name = portList[i]; comboBox.Items.Add(name); }
串口屬性參數設置
SerialPort類所包含的屬性詳見下表。

串口發送信息
SerialPort類定義了多種方法用于串口發送信息。
Write(Byte[], Int32, Int32) 使用緩沖區中的數據將指定數量的字節寫入串行端口
Write(Char[], Int32, Int32) 使用緩沖區中的數據將指定數量的字符寫入串行端口
Write(String) 將指定的字符串寫入串行端口
WriteLine(String) 將指定的字符串和NewLine值寫入輸出緩沖區
下面是一個簡單的例子說明如何通過串口發送字符串和字節數據:
using System.IO.Ports; private static void SendSampleData() { // Instantiate the communications // port with some basic settings SerialPort port = new SerialPort( "COM1", 9600, Parity.None, 8, StopBits.One); // Open the port for communications port.Open(); // Write a string port.Write("Hello World"); // Write a set of bytes port.Write(new byte[] { 0x0A, 0xE2, 0xFF }, 0, 3); // Close the port port.Close(); }
下面是如何發送一個文本文件的例子:
private static void SendTextFile(SerialPort port, string FileName) { port.Write(File.OpenText(FileName).ReadToEnd()); }
下面是如何發送一個二進制文件的例子:
private static void SendBinaryFile(SerialPort port, string FileName) { using (FileStream fs = File.OpenRead(FileName)) port.Write((new BinaryReader(fs)).ReadBytes((int)fs.Length), 0, (int)fs.Length); }
串口接收信息
SerialPort類定義了多種方法用于串口接收信息。
Read(Byte[], Int32, Int32) 從SerialPort輸入緩沖區讀取一些字節,并將那些字節寫入字節數組中指定的偏移量處
Read(Byte[], Int32, Int32) 從SerialPort輸入緩沖區讀取一些字符,并將那些字符寫入字符數組中指定的偏移量處
ReadByte() 從SerialPort輸入緩沖區中同步讀取一個字節
ReadChar() 從SerialPort輸入緩沖區中同步讀取一個字符
ReadExisting() 在編碼的基礎上,讀取SerialPort對象的流和輸入緩沖區中所有立即可用的字節
ReadLine() 一直讀取到輸入緩沖區中的NewLine值
ReadTo(String) 一直讀取到輸入緩沖區中的指定value的字符串
通常一個比較常見的用法就是將串口里面立即能用的字符或數據讀取然后打印在textbox等控件中顯示。
#region Namespace Inclusions using System; using System.IO.Ports; using System.Windows.Forms; #endregion namespace SerialPortExample { class SerialPortProgram { // Create the serial port with basic settings private SerialPort port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One); [STAThread] static void Main(string[] args) { // Instatiate this class new SerialPortProgram(); } private SerialPortProgram() { Console.WriteLine("Incoming Data:"); // Attach a method to be called when there // is data waiting in the port's buffer port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); // Begin communications port.Open(); // Enter an application loop to keep this thread alive Application.Run(); } private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) { // Show all the incoming data in the port's buffer Console.WriteLine(port.ReadExisting()); } } }
下面是一段我在工作中實際運用
/// <summary> /// 初始化com /// </summary> /// <exception cref="NotImplementedException"></exception> private void InitializePort() { try { string[] portList = System.IO.Ports.SerialPort.GetPortNames(); //臥式 if (portList.Contains(ConfigurationManager.ConnectionStrings["com"].ConnectionString)) { port = new SerialPort(ConfigurationManager.ConnectionStrings["com"].ConnectionString);//com口 if (!port.IsOpen) { port.BaudRate = int.Parse("9600"); port.Parity = Parity.None; port.StopBits = StopBits.One; port.DataBits = 8; port.Handshake = Handshake.None; port.Encoding = Encoding.UTF8; port.DataReceived += new SerialDataReceivedEventHandler(datareceive); port.Open(); } } //站式 if (portList.Contains(ConfigurationManager.ConnectionStrings["com1"].ConnectionString)) { port1 = new SerialPort(ConfigurationManager.ConnectionStrings["com1"].ConnectionString);//com口 if (!port1.IsOpen) { port1.BaudRate = int.Parse("9600"); port1.Parity = Parity.None; port1.StopBits = StopBits.One; port1.DataBits = 8; port1.Handshake = Handshake.None; port1.Encoding = Encoding.UTF8; port1.DataReceived += new SerialDataReceivedEventHandler(datareceive); port1.Open(); } } } catch { return; } } private void datareceive(object sender, SerialDataReceivedEventArgs e) { try { Thread.Sleep(100); SerialPort seport = (SerialPort)sender; string res = null;// port.ReadExisting(); if (seport.BytesToRead > 9) { port1.Encoding = Encoding.GetEncoding("gb2312"); res = port1.ReadExisting(); } else { byte[] rec = new byte[seport.BytesToRead]; seport.Read(rec, 0, seport.BytesToRead); string[] reddd = BitConverter.ToString(rec).Split('-'); string hei = reddd[2].ToString() + reddd[3].ToString(); string wei = reddd[4].ToString() + reddd[5].ToString(); res = "W:" + Convert.ToInt32(wei, 16) + " H1:" + Convert.ToInt32(hei, 16); } if (res != null && res!="") { //this.Invoke(new Action(() => { textBox3.Text = res; })); string[] wh = res.Split(' '); string w = "", h = ""; if (!string.IsNullOrEmpty(wh[0])) { w = wh[0]; if (w.Replace("W:", "").Substring(0, 1) == "0") { string w1 = w.Replace("W:0", "").Replace(".", ""); if (w1.Length == 3) { w = w.Replace("W:0", "").Replace(".", "").Insert(1, "."); } if (w1.Length == 4) { w = w.Replace("W:0", "").Replace(".", "").Insert(2, "."); } } else { string w1 = w.Replace("W:", "").Replace(".", ""); if (w1.Length==3) { w = w.Replace("W:", "").Replace(".", "").Insert(1,"."); } if (w1.Length == 4) { w = w.Replace("W:", "").Replace(".", "").Insert(2, "."); } } } if (!string.IsNullOrEmpty(wh[1])) { h = wh[1]; if (h.Contains("H1")) { if (h.Replace("H1:", "").Substring(0, 1) == "0") { h = h.Replace("H1:0", "").Replace(".", "").Insert(2, "."); } else { string h1 = h.Replace("H1:", "").Replace(".", ""); if(h1.Length==2) { h = h.Replace("H1:", "").Replace(".", "").Insert(2, "."); } if (h1.Length == 3) { h = h.Replace("H1:", "").Replace(".", "").Insert(2, "."); } if (h1.Length==4) { h = h.Replace("H1:", "").Replace(".", "").Insert(3, "."); } } } else { if (h.Replace("H:", "").Substring(0, 1) == "0") { h = h.Replace("H:0", "").Replace(".", "").Insert(3, "."); } else h = h.Replace("H:", "").Replace(".", "").Insert(3, "."); } } Invoke((EventHandler)delegate { tizhong.Text = w; }); Invoke((EventHandler)delegate { shengao.Text = h; }); } else { } } catch { } }
浙公網安備 33010602011771號