在C#中使用SerialPort類實現串列埠通訊
表1 SerialPort類的常用屬性
名 稱 |
說 明 |
BaseStream |
獲取 SerialPort 物件的基礎 Stream 物件 |
BaudRate |
獲取或設定序列波特率 |
BreakState |
獲取或設定中斷訊號狀態 |
BytesToRead |
獲取接收緩衝區中資料的位元組數 |
BytesToWrite |
獲取傳送緩衝區中資料的位元組數 |
CDHolding |
獲取埠的載波檢測行的狀態 |
CtsHolding |
獲取“可以傳送”行的狀態 |
DataBits |
獲取或設定每個位元組的標準資料位長度 |
DiscardNull |
獲取或設定一個值,該值指示 Null 位元組在埠和接收緩衝區之間傳輸時是否被忽略 |
DsrHolding |
獲取資料設定就緒 (DSR) 訊號的狀態 |
DtrEnable |
獲取或設定一個值,該值在序列通訊過程中啟用資料終端就緒 (DTR) 訊號 |
Encoding |
獲取或設定傳輸前後文本轉換的位元組編碼 |
Handshake |
獲取或設定串列埠資料傳輸的握手協議 |
IsOpen |
獲取一個值,該值指示 SerialPort 物件的開啟或關閉狀態 |
NewLine |
獲取或設定用於解釋 ReadLine( )和WriteLine( )方法呼叫結束的值 |
Parity |
獲取或設定奇偶校驗檢查協議 |
續表
名 稱 |
說 明 |
ParityReplace |
獲取或設定一個位元組,該位元組在發生奇偶校驗錯誤時替換資料流中的無效位元組 |
PortName |
獲取或設定通訊埠,包括但不限於所有可用的 COM 埠 |
ReadBufferSize |
獲取或設定 SerialPort 輸入緩衝區的大小 |
ReadTimeout |
獲取或設定讀取操作未完成時發生超時之前的毫秒數 |
ReceivedBytesThreshold |
獲取或設定 DataReceived 事件發生前內部輸入緩衝區中的位元組數 |
RtsEnable |
獲取或設定一個值,該值指示在序列通訊中是否啟用請求傳送 (RTS) 訊號 |
StopBits |
獲取或設定每個位元組的標準停止位數 |
WriteBufferSize |
獲取或設定串列埠輸出緩衝區的大小 |
WriteTimeout |
獲取或設定寫入操作未完成時發生超時之前的毫秒數 |
表2 SerialPort類的常用方法
方 法 名 稱 |
說 明 |
Close |
關閉埠連線,將 IsOpen 屬性設定為False,並釋放內部 Stream 物件 |
Open |
開啟一個新的串列埠連線 |
Read |
從 SerialPort 輸入緩衝區中讀取 |
ReadByte |
從 SerialPort 輸入緩衝區中同步讀取一個位元組 |
ReadChar |
從 SerialPort 輸入緩衝區中同步讀取一個字元 |
ReadLine |
一直讀取到輸入緩衝區中的 NewLine 值 |
ReadTo |
一直讀取到輸入緩衝區中指定 value 的字串 |
Write |
已過載。將資料寫入串列埠輸出緩衝區 |
WriteLine |
將指定的字串和 NewLine 值寫入輸出緩衝區 |
使用SerialPort類的方法:
方法一:
首先要新增
using System.IO;
using System.IO.Ports;
1...在類的內部定義SerialPort com;
2...開啟串列埠
com = new SerialPort();
com.BaudRate = 115200;
com.PortName = "COM1";
com.DataBits = 8;
com.Open();//開啟串列埠
3...傳送資料
Byte[] TxData ={1,2,3,4,5,6,7,8 };
com.Write(TxData, 0, 8);
4...接收資料
4.1使用事件接收
this.com.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
4.2使用執行緒接收
接收資料啟動一個執行緒,使其接收。
在類的內部定義
Thread _readThread;
bool _keepReading;
開啟串列埠後啟動執行緒
_keepReading = true;
_readThread = new Thread(ReadPort);
_readThread.Start();
執行緒函式
<textarea cols="50" rows="15" name="code" class="c-sharp"> private void ReadPort() { while (_keepReading) { if (com.IsOpen) { byte[] readBuffer = new byte[com.ReadBufferSize + 1]; try { // If there are bytes available on the serial port, // Read returns up to "count" bytes, but will not block (wait) // for the remaining bytes. If there are no bytes available // on the serial port, Read will block until at least one byte // is available on the port, up until the ReadTimeout milliseconds // have elapsed, at which time a TimeoutException will be thrown. int count = com.Read(readBuffer, 0, com.ReadBufferSize); String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count); if (count != 0) //byteToHexStr(readBuffer); ThreadFunction(byteToHexStr(readBuffer,count)); } catch (TimeoutException) { } } else { TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50); Thread.Sleep(waitTime); } } }</textarea>
方法二:使用C#自帶的SerialPor控制元件。
1...在“工具箱”的“元件”中選擇SerialPor控制元件新增。
2...設定串列埠並開啟
serialPort1.PortName = "COM1";
serialPort1.BaudRate = 9600;
serialPort1.Open();
3...寫入資料可以使用Write或者下面的函式
serialPort1.WriteLine(str);
4...新增資料接收的事件
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
使用中的一些常見問題
C#中SerialPort類中DataReceived事件GUI實時處理方法(來自[email protected] 的看法)
MSDN:從 SerialPort 物件接收資料時,將在輔助執行緒上引發 DataReceived 事件。由於此事件在輔助執行緒而非主執行緒上引發,因此嘗試修改主執行緒中的一些元素(如 UI 元素)時會引發執行緒異常。如果有必要修改主 Form 或 Control 中的元素,必須使用 Invoke 回發更改請求,這將在正確的執行緒上執行.進而要想將輔助執行緒中所讀到的資料顯示到主執行緒的Form控制元件上時,只有通過Invoke方法來實現
下面是程式碼例項:
<textarea cols="50" rows="15" name="code" class="c-sharp">private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { int SDateTemp = this.serialPort1.ReadByte(); //讀取串列埠中一個位元組的資料 this.tB_ReceiveDate.Invoke( //在擁有此控制元件的基礎視窗控制代碼的執行緒上執行委託Invoke(Delegate)
//即在textBox_ReceiveDate控制元件的父視窗form中執行委託. new MethodInvoker( /*表示一個委託,該委託可執行託管程式碼中宣告為 void 且不接受任何引數的任何方法。 在對控制元件的 Invoke 方法進行呼叫時或需要一個簡單委託又不想自己定義時可以使用該委託。*/ delegate{ /*匿名方法,C#2.0的新功能,這是一種允許程式設計師將一段完整程式碼區塊當成引數傳遞的程式程式碼編寫技術,通過此種方法可 以直接使用委託來設計事件響應程式以下就是你要在主執行緒上實現的功能但是有一點要注意,這裡不適宜處理過多的方法,因為C#訊息機制是訊息流水線響應機制,如果這裡在主執行緒上處理語句的時間過長會導致主UI執行緒阻塞,停止響應或響應不順暢,這時你的主form介面會延遲或卡死
*/ this.tB_ReceiveDate.AppendText(SDateTemp.ToString());//輸出到主視窗文字控制元件 this.tB_ReceiveDate.Text += " ";} ) ); }</textarea>
如何知道當前電腦有哪個串列埠
在窗體上新增一個comboBox控制元件。
然後使用comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames()); 或者
string[] portList = System.IO.Ports.SerialPort.GetPortNames();
for (int i = 0; i < portList.Length; ++i)
{
string name = portList[i];
comboBox1.Items.Add(name);
}