2012-12-06 28 views
20

我已經閱讀了很多關於如何使用.NET SerialPort類從串口讀取數據的問題,但沒有一種推薦方法對我來說已經證明是完全有效的。使用.NET框架讀取串行端口的正確方法是什麼?

這裏是我用現在的代碼:

SerialPort port = new SerialPort("COM1"); 
port.DataReceived += new SerialDataReceivedEventHandler(MyDataReceivedHandler); 

和事件處理程序:

void MyDataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
{ 
    int count = port.BytesToRead; 
    byte[] ByteArray = new byte[count]; 
    port.Read(ByteArray, 0, count); 
} 

但我仍然有時會丟失一些數據。我嘗試了不同的方式來閱讀事件處理程序中的數據,但沒有運氣。

由於.NET 4.5帶來了一些新的可能性來完成一些異步任務,例如ReadAsync方法似乎可以用在串口數據流上,我很好奇看到什麼是處理這些情況的推薦方法。

+3

您的問題是非常含糊。 「有時候我仍然錯過了一些數據」就像告訴你的機械師「我的車有時會發出有趣的噪音」,並詢問需要多少費用才能修復。也許[這個答案](http://stackoverflow.com/a/2966357/62576)相關的問題可能會有所幫助。但是,如果你需要幫助,我認爲你需要更加具體。事實上,沒有太多的東西不能通過查看關於這個主題的其他問題來回答。 –

+0

你是對的,我會把一個真實的例子放在一起,以更好地說明發生了什麼...... –

+3

通過RS232或485實現串行通信協議是一項非常非常艱鉅的任務。它需要很多的經驗。自從老DOS時代以來,我一直在執行這個操作,但仍然陷入了一些常見的陷阱。你爲什麼不嘗試找到一個可靠的第三方產品來處理串行通信?他們可能已經解決了你會陷入自己的所有許多錯誤:-)如果這是一個練習,那麼繼續,它會給予終端掌握串行通信非常滿意! :-) – Loudenvier

回答

14

你能嘗試這樣的事情,例如我想你是想利用的是port.ReadExisting()方法

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()); 
    } 
} 

或者是你要根據做什麼你試圖這樣做,你可以試試這個

public class MySerialReader : IDisposable 
{ 
    private SerialPort serialPort; 
    private Queue<byte> recievedData = new Queue<byte>(); 

    public MySerialReader() 
    { 
    serialPort = new SerialPort(); 
    serialPort.Open(); 
    serialPort.DataReceived += serialPort_DataReceived; 
    } 

    void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e) 
    { 
    byte[] data = new byte[serialPort.BytesToRead]; 
    serialPort.Read(data, 0, data.Length); 
    data.ToList().ForEach(b => recievedData.Enqueue(b)); 
    processData(); 
    } 

    void processData() 
    { 
    // Determine if we have a "packet" in the queue 
    if (recievedData.Count > 50) 
    { 
     var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue()); 
    } 
    } 

    public void Dispose() 
    { 
     if (serialPort != null) 
     { 
      serialPort.Dispose(); 
     } 
    } 
+1

感謝您的幫助,我終於用'ReadExisting'與阻塞集合一起使用。我仍然計劃嘗試新的'ReadAsync'函數,儘管... –

+0

processData()方法不需要互斥鎖嗎?我的意思是,當processData()仍在運行時,datareceived事件可能再次觸發?不是嗎?所以我們最終可能會在processData()方法內運行兩個(或更多?)線程.... –

+0

我還沒有嘗試過這種程度,並基於Yannick在他上面的評論中提到的內容,我認爲它會如果他要繼續閱讀異步,沒有什麼不同 – MethodMan

4

我用類似的代碼@MethodMan,但我必須保持串口進行發送數據的跟蹤和尋找終止字符知道串口已完成發送時數據。

private string buffer { get; set; } 
private SerialPort _port { get; set; } 

public Port() 
{ 
    _port = new SerialPort(); 
    _port.DataReceived += new SerialDataReceivedEventHandler(dataReceived); 
    buffer = string.Empty; 
} 

private void dataReceived(object sender, SerialDataReceivedEventArgs e) 
{  
    buffer += _port.ReadExisting(); 

    //test for termination character in buffer 
    if (buffer.Contains("\r\n")) 
    { 
     //run code on data received from serial port 
    } 
} 
0

我想不要使用SerialDataReceivedEvent。定時器是一個更好的選擇,並在一段時間後,以接收數據:

For i = 1 To Me.objSerialPort.BytesToRead 
    strReceiveData &= Convert.ToChar(Me.objSerialPort.ReadByte) 
Next i 
相關問題