2

シリアルポートを介して定期的にデータを受信して​​います。これをプロットして、さらに多くのことを行うためです。この目的を達成するために、各パケットの長さを指定するヘッダーを使用して、マイクロコントローラーからコンピューターにデータを送信します。

最後の1つの詳細を除いて、プログラムは完全に実行および動作しています。ヘッダーが長さを指定している場合、そのバイト数に達するまでプログラムは停止しません。したがって、何らかの理由で1つのパケットの一部のデータが失われた場合、プログラムは待機して次のパケットの開始を取得します...その後、実際の問題を開始します。その瞬間以来、すべてが失敗します。

私は0.9秒ごとにタイマーを上げることを考えました(パッケージは毎秒来る)。これは、変数を待ってリセットするために戻ってくるためにコマンドを出します。方法がわからないので試してみましたが、実行中にエラーが発生します。IndCom(次のコードを参照)が一部の関数の途中でリセットされ、「インデックスが範囲外」になるとエラーが発生するため。

コードを添付します(タイマーなし)

private void routineRx(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        try
        {
            int BytesWaiting;


            do
            {
                BytesWaiting = this.serialPort.BytesToRead;
                //Copy it to the BuffCom
                while (BytesWaiting > 0)
                {
                    BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
                    IndCom = IndCom + 1;
                    BytesWaiting = BytesWaiting - 1;
                }

            } while (IndCom < HeaderLength);
            //I have to read until I got the whole Header which gives the info about the current packet

            PacketLength = getIntInfo(BuffCom,4);

            while (IndCom < PacketLength)
            {
                BytesWaiting = this.serialPort.BytesToRead;
                //Copy it to the BuffCom
                while (BytesWaiting > 0)
                {
                    BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
                    IndCom = IndCom + 1;
                    BytesWaiting = BytesWaiting - 1;
                }
             }

            //If we have a packet--> check if it is valid and, if so, what kind of packet is
            this.Invoke(new EventHandler(checkPacket));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }

私はオブジェクト指向プログラミングとc#に慣れていないので、気を付けてください。そして、どうもありがとうございました

4

1 に答える 1

1

あなたがするかもしれないことはストップウォッチを使うことです。

const long COM_TIMEOUT = 500;

Stopwatch spw = new Stopwatch();
spw.Restart();
while (IndCom < PacketLength)
{
    //read byte, do stuff
    if (spw.ElapsedMilliseconds > COM_TIMEOUT) break;  //etc
}

最初にストップウォッチを再起動し、各whileループの時間を確認してから、タイムアウトが発生した場合はブレークアウト(およびクリーンアップ)します。数バイトしか期待していない場合でも、900msは多分多すぎます。Comのトラフィックは非常に高速です。すべてをすぐに取得できなければ、おそらく来ないでしょう。

通信プロトコル([CR]など)で終了文字を使用するのが好きです。これにより、終了文字が見つかるまで読み取り、停止することができます。これにより、次のコマンドを読み取ることができなくなります。終了文字を使用したくない場合でも、コードを次のように変更します。

 while (IndCom < PacketLength)
 {
     if (serialPort.BytesToRead > 0) 
     {
         BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
         IndCom++;             
     }
  }

パケットサイズに達したときに停止し、残りの文字を次のラウンドスルー(つまり、次のコマンド)のためにバッファに残します。上記でストップウォッチタイムアウトを追加することもできます。

終了文字のもう1つの優れた点は、パケットの長さを事前に知る必要がないことです。終了文字に到達するまで読み取り、取得したらすべてを処理/解析します。これにより、2ステップのポートが1ステップのポート読み取りに読み込まれます。

于 2012-11-26T12:05:51.480 に答える