12

Readline() を使用してみましたが、データがドロップされました。Read() を使用してみましたが、エラーを防止する方法がわかりません。複数のパケットを次々に取得する可能性があり、知る方法がないためです。別のパケットが入ってくるということです。パケットの間の BytesToRead は 0 なので、使用できません。バッファにデータを読み取るときに、タイマーを使用するか、スレッドをスリープ状態にして、すべてのパケットが到着できるようにしますか?

迷っています。次に何を試せばよいかわからない。

シリアル ポートから出力される文字列が \n または \r または \r\n で終了するという保証はありません。ユーザーが PRINT を押したときにスケールから来るすべてのパケットを読み取るための絶対確実な方法が必要です。

誰かが私が好きなアイデアでここに答えました-すべてのパケットを一定時間待っていましたが、彼らは答えを消しました. 再投稿できる可能性はありますか?

4

3 に答える 3

22

クラスのDataRecievedイベントを聞いてみましたか?SerialPort

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();
    }
于 2009-03-13T23:28:38.143 に答える
10

少し前に同じプロセスを経ました。

「パケット」を読み取る唯一の方法は、パケットの開始と終了がストリーム内のどこにあるかという概念を持つことです。

msdnから:

SerialPort クラスはデータをバッファリングしますが、BaseStream プロパティに含まれるストリームはバッファリングしないため、読み取り可能なバイト数に関して 2 つの競合が発生する可能性があります。BytesToRead プロパティは、読み取るバイトがあることを示すことができますが、これらのバイトは、SerialPort クラスにバッファリングされているため、BaseStream プロパティに含まれるストリームにアクセスできない可能性があります。

バックラウンド スレッド (BackgroundWorker を使用できます) を使用して、データをバッファーに読み込みました。SerialPort.Newline プロパティを使用して終端文字を確実に設定できない場合 (たとえば、変化するため)、ブロッキング SerialPort.Readline() を使用できないため、独自のパケット検出システムを実装する必要があります。方法。

SerialPort.Read() (または SerialPort.ReadExisting() メソッドを使用した文字列) を使用してバイト バッファーに読み込み、データ内に有効なパケットを検出したときにイベントを生成することができます。Read() (および ReadExisting() と仮定します) は SerialPort のバッファを空にするため、データを別の場所に保持する必要があることに注意してください。

SerialPort.ReadTimeout を設定すると、TimeoutException を処理でき、デバイスが送信していない状態を簡単に処理できます。これは、固定バイト数を使用している場合、またはその他の終了していないスキームを使用している場合に、パケット検出をリセットする良い方法です。(部分的なパケットが必要ない場合は、タイムアウト時に SerialPort.DiscardInBuffer() を使用します)。

幸運を

于 2009-03-14T00:00:55.583 に答える
4

バイトはいつでも入ってくる可能性があるため、入ってくるデータのバッファリングは重要です。だからあなたはすべきです

  1. 受信データをバッファリングする
  2. バッファをスキャンして完全なデータを見つける
  3. バッファから使用済みデータを削除します

シリアルポートにまだ問題があるかどうか疑問に思っています. もしそうなら、私は C# でシリアル ポート プログラミング言語を開発しました。誰もが遭遇するほとんどすべての問題を解決できると信じています。

是非一度ご覧になってみてはいかがでしょうか?例えば; 次のようにシリアルポートからの着信データをバッファリングし、文字列操作を簡単に行うことができます。

state Init
  // define a global variable
  our $BUFFER = "";
  jump(Receive);
end state

state Receive
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    $BUFFER += $DATA_PACKET;
    call(Parser);
  }
end state

state Parser
  // check if buffer matchs regular expression pattern
  if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) {
    // Received complete data
    $lenData = length($WILLDELETE);
    $BUFFER = remove($BUFFER, 0, $lenData);

    // Do operations with the other parsed fields. $DATA and $CHECKSUM in this example.
  }
end state

プロジェクトは sourceforge で無料で入手できます。ご不明な点がございましたら、お気軽にお問い合わせください。

プロジェクトホームページ

リンクをダウンロード

于 2010-10-29T11:37:14.503 に答える