2012-12-06 14 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では、SerialPortストリームで使用可能なような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

あなたの助けてくれてありがとう、私はついにBlockingコレクションで使われた 'ReadExisting'に行きました。私はまだ新しい 'ReadAsync'関数を試すつもりです... –

+0

processData()メソッドにはミューテックスが必要ですか?つまり、processData()がまだ実行されているときに、datareceivedイベントが再びトリガーされる可能性があります。ではない?ですから、processData()メソッドの中で2つ(あるいはそれ以上)のスレッドが実行されてしまうことになりました.... –

+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を使用しないでください。タイマーは良い選択の1つで、一定の時間が経過した後、データを受け取る:

For i = 1 To Me.objSerialPort.BytesToRead 
    strReceiveData &= Convert.ToChar(Me.objSerialPort.ReadByte) 
Next i 
関連する問題