串列埠通訊原理
串列埠通訊(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 { } }