關於串行接口
源文:http://www.cnblogs.com/zhuawang/archive/2013/05/31/3111565.html
串行接口(Serial port)又稱“串口”,主要用於串行式逐位數據傳輸。常見的有一般電腦應用的RS-232(使用 25 針或 9 針連接器)和工業電腦應用的半雙工RS-485與全雙工RS-422。
串行接口按電氣標準及協議來分,包括RS-232-C、RS-422、RS485、USB等。 RS-232-C、RS-422與RS-485標準只對接口的電氣特性做出規定,不涉及接插件、電纜或協議。USB是近幾年發展起來的新型接口標準,主要應用於高速數據傳輸領域。
RS-232-C
也稱標準串口,是目前最常用的一種串行通訊接口。它是在1970年由美國電子工業協會(EIA)聯合貝爾系統、 調制解調器廠家及計算機終端生產廠家共同制定的用於串行通訊的標準。它的全名是“數據終端設備(DTE)和數據通訊設備(DCE)之間串行二進制數據交換接口技術標準”。傳統的RS-232-C接口標準有22根線,採用標準25芯D型插頭座。自IBM PC/AT開始使用簡化了的9芯D型插座。至今25芯插頭座現代應用中已經很少採用。電腦一般有兩個串行口:COM1和COM2,9針D形接口通常在計算機後面能看到。現在有很多手機數據線或者物流接收器都採用COM口與計算機相連。RS-422
爲改進RS-232通信距離短、速率低的缺點,RS-422定義了一種平衡通信接口,將傳輸速率提高到10Mb/s,傳輸距離延長到4000英尺(速率低於100kb/s時),並允許在一條平衡總線上連接最多10個接收器。RS- 422是一種單機發送、多機接收的單向、平衡傳輸規範,被命名爲TIA/EIA-422-A標準。RS-485
爲擴展應用範圍,EIA又於1983年在RS-422基礎上制定了RS-485 標準,增加了多點、雙向通信能力,即允許多個發送器連接到同一條總線上,同時增加了發送器的驅動能力和衝突保護特性,擴展了總線共模範圍,後命名爲 TIA/EIA-485-A標準。Universal Serial Bus(通用串行總線)
簡稱USB,是目前電腦上應用較廣泛的接口規範,由Intel、Microsoft、Compaq、IBM、NEC、Northern Telcom等幾家大廠商發起的新型外設接口標準。USB接口是電腦主板上的一種四針接口,其中中間兩個針傳輸數據,兩邊兩個針給外設供電。USB接口速度快、連接簡單、不需要外接電源,傳輸速度12Mbps,新的USB 2.0可達480Mbps;電纜最大長度5米,USB電纜有4條線:2條信號線,2條電源線,可提供5伏特電源,USB電纜還分屏蔽和非屏蔽兩種,屏蔽電纜傳輸速度可達12Mbps,價格較貴,非屏蔽電纜速度爲1.5Mbps,但價格便宜;USB通過串聯方式最多可串接127個設備;支持熱插拔。最新的規格是USB 3.0。RJ-45接口
是以太網最爲常用的接口,RJ45是一個常用名稱,指的是由IEC(60)603-7標準化,使用由國際性的接插件標準定義的8個位置(8針)的模塊化插孔或者插頭。
串口屬性
1. PortName 串口名 默認值COM1
串口對於操作系統來說是一個文件,如果設置PortName爲本機不存在的串口名(即文件名),如“COM7”或“COMK”,Open()打開串口將失敗,提示“端口COM7不存在”。
2. BaudRate 獲取或設置串行波特率bit/s 默認值9600
比特率=波特率X單個調製狀態對應的二進制位數。
RS232是要用在近距離傳輸上最大距離爲30M
RS485用在長距離傳輸最大距離1200M
3. DataBits 獲取或設置每個字節的標準數據位長度 默認值8
當計算機發送一個信息包,實際的數據不會是8位的,標準的值是5、7和8位。如何設置取決於你想傳送的信息。比如,標準的ASCII碼是0~127(7位)。擴展的ASCII碼是0~255(8位)。如果數據使用簡單的文本(標準 ASCII碼),那麼每個數據包使用7位數據。每個包
是指一個字節,包括開始/停止位,數據位和奇偶校驗位。由於實際數據位取決於通信協議的選取,術語“包”指任何通信的情況。
4. StopBits 獲取或設置每個字節的標準停止位數 默認值One
用於表示單個包的最後一位。典型的值爲1,1.5和2位。由於數據是在傳輸線上定時的,並且每一個設備有其自己的時鐘,很可能在通信中兩臺設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,並且提供計算機校正時鐘同步的機會。適用於停止位的位數
越多,不同時鐘同步的容忍程度越大,但是數據傳輸率同時也越慢。
5. Parity 獲取或設置奇偶校驗檢查協議 默認值None
在串口通信中一種簡單的檢錯方式。有四種檢錯方式:偶、奇、高和低。當然沒有校驗位也是可以的。對於偶和奇校驗的情況,串口會設置校驗位(數據位後面的一位),用一個值確保傳輸的數據有偶個或者奇個邏輯高位。例如,如果數據是011,那麼對於偶校驗,校驗
位爲0,保證邏輯高的位數是偶數個。如果是奇校驗,
校驗位位1,這樣就有3個邏輯高位。高位和低位不真正的檢查數據,簡單置位邏輯高或者邏輯低校驗。這樣使得接收設備能夠知道一個位的狀態,有機會判斷是否有噪聲干擾了通信或者是否傳輸和接收
串口(COM)讀寫操作的三種方式:
第1種方式是採用微軟在.NET2.0推出了一個串口控件,SerialPort類,但必須是.NET2.0纔可以。
第2種方式是用API寫串口通信,雖然難度高,但可以方便實現自己想要的各種功能。
第3種方式是通過採用Visual Studio 6.0中原來的MSComm控件這是最簡單的,最方便的方法,但需要註冊。
在.NET下關於串口的操作以及相關方法事件:
在.NET 2.0+以上,已經提供了關於串口操作的組件
能夠很方便的操作串口進行數據的讀寫
對於一些重要的方法以及事件解釋如下:
1. Open() 打開一個新的串行端口連接
2. Close() 關閉端口連接,將 IsOpen 屬性設置爲 false,並釋放內部 Stream 對象
3. Read(Byte[], int, int) 輸入緩衝區讀取一些字節並將那些字節寫入字節數組中指定的偏移量處
4. ReadByte() 從 SerialPort 輸入緩衝區中同步讀取一個字節
5. ReadChar() 從 SerialPort 輸入緩衝區中同步讀取一個字符
6. ReadExisting() 在編碼的基礎上,讀取 SerialPort 對象的流和輸入緩衝區中所有立即可用的字節
6. ReadLine() 一直讀取到輸入緩衝區中的 NewLine 值
7. ReadTo() 一直讀取到輸入緩衝區中的指定 value 的字符串
8. Write(string) 將指定的字符串寫入串行端口
9. Write(Byte[], int, int) 使用緩衝區的數據將指定數量的字符寫入串行端口
10. WriteLine() 將指定字符串和NewLine值寫入輸出緩衝區
11. DiscardInBuffer() 丟棄接收緩衝區的數據
12. DiscardOutBuffer() 丟棄發送緩衝區的數據
12. static GetPortNanes() 獲取當前計算機的串口名稱數組
13. DataReceive事件 數據接收事件的方法
不保證對接收到的每個字節引發 DataReceived 事件。 使用 BytesToRead 屬性確定緩衝區中剩餘的要讀取的數據量。從 SerialPort 對象接收數據時,將在輔助線程上引發 DataReceived 事件。
14. PinChanged事件 串行管腳更改事件的方法
在 SerialPort 對象進入 BreakState 時引發,但在端口退出 BreakState 時不引發。將在輔助線程上引發 PinChanged 事件。
15. ErrorReceived事件 錯誤事件的方法
如果在流的尾字節上出現奇偶校驗錯誤,將向輸入緩衝區添加一個值爲 126 的額外字節。將在輔助線程上引發 PinChanged 事件。
代碼例子:
#region 打開串口 privatevoid btnOpenCom_Click(object sender, EventArgs e) { string _sCom = string.Empty;//串口號if (CheckIsSltCom(ref _sCom)) { try { string _sDateBits = this.cbDateBits.Text.Trim();//數據位string _sBondRate = this.cbBondRate.Text.Trim();//波特率string _sStopBit = this.cbStopBit.Text.Trim();//停止位string _sParity = this.cbParity.Text.Trim();//效驗 InitOpenCom(_sCom, _sDateBits, _sBondRate, _sParity, _sStopBit); toolStripStatusLabel.Text = string.Format("成功打開串口號:{0}.", _sCom); } catch (Exception ex) { toolStripStatusLabel.Text = string.Format("打開串口號:{0}失敗!原因:{1}.", _sCom, ex.Message.Trim()); serialPort.Dispose(); } finally { WriteLog(toolStripStatusLabel.Text, LogType.Wirtelog); } } } #endregion
#region 初始化串口 privatevoid InitOpenCom(string _sCom, string _sDateBits, string _sBondRate, string _sParity, string _sStopBit) { if (serialPort.IsOpen) serialPort.Close(); serialPort.PortName = _sCom; serialPort.BaudRate = Convert.ToInt32(_sBondRate); serialPort.DataBits = Convert.ToInt32(_sDateBits); switch (_sStopBit) { case"1": serialPort.StopBits = StopBits.One; break; case"1.5": serialPort.StopBits = StopBits.OnePointFive; break; case"2": serialPort.StopBits = StopBits.Two; break; default: serialPort.StopBits = StopBits.None; break; } serialPort.DataBits = Convert.ToInt32(_sDateBits); switch (_sParity) { case"偶": serialPort.Parity = Parity.Even; break; case"奇": serialPort.Parity = Parity.Odd; break; case"空格": serialPort.Parity = Parity.Space; break; case"標誌": serialPort.Parity = Parity.Mark; break; case"無": serialPort.Parity = Parity.None; break; } serialPort.Open(); } #endregion
#region 判斷選擇串口是否合法 privatebool CheckIsSltCom(refstring _sCom) { if (string.IsNullOrEmpty(cbCom.Text.Trim())) { DevOperate.ShowToolTip<ComboBoxEdit>(toolTipController, "請選擇串口號!", cbCom); returnfalse; } _sCom = cbCom.Text.Trim(); returntrue; } #endregion
#region 關閉串口 privatevoid btnCloseCom_Click(object sender, EventArgs e) { string _sCom = string.Empty;//串口號if (CheckIsSltCom(ref _sCom)) { try { if (serialPort.IsOpen) serialPort.Close(); toolStripStatusLabel.Text = string.Format("成功關閉串口號:{0}.", _sCom); } catch (Exception ex) { toolStripStatusLabel.Text = string.Format("關門串口號:{0}失敗!原因:{1}.", _sCom, ex.Message.Trim()); serialPort.Dispose(); } finally { WriteLog(toolStripStatusLabel.Text, LogType.Wirtelog); } } } #endregion
#region 串口數據接收事件 privatestring sComStr = string.Empty; privatevoid serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { byte[] _readBuffer = newbyte[serialPort.ReadBufferSize]; lock (_readBuffer.SyncRoot) { int _nBytesRead = serialPort.Read(_readBuffer, 0, _readBuffer.Length); string _sStrTmpCom = ByteHelper.byteToHexStr(_readBuffer, _nBytesRead); ; sComStr += _sStrTmpCom; if (OnSerialPortReceived != null) OnSerialPortReceived(_sStrTmpCom); if (!ckComReciveFilter.Checked) WriteLog(string.Format("接收:{0}.", _sStrTmpCom), LogType.Wirtelog); if (sComStr.StartsWith("68") && sComStr.EndsWith("16")) { if (ckComReciveFilter.Checked) WriteLog(string.Format("接收:{0}.", sComStr), LogType.Wirtelog); if (OnSerialPortReceivedBys != null) OnSerialPortReceivedBys(ByteHelper.HexStrToByteArray(sComStr), 0); sComStr = string.Empty; _readBuffer = null; } } } catch (Exception ex) { WriteLog(string.Format("接收異常,原因:{0}", ex.Message.Trim()), LogType.DialogLog); } } #endregion
運行效果