5

シリアル インターフェイス経由で接続したい 2 つのデバイスがありますが、接続に互換性がありません。この問題を回避するために、両方を PC に接続し、COM ポート X のトラフィックを COM ポート Y に、またはその逆にルーティングする C# プログラムに取り組んでいます。

プログラムは 2 つの COM ポートに接続します。データ受信イベント ハンドラーで、受信データを読み取り、それを他の COM ポートに書き込みます。これを行うには、次のコードがあります。

    private void HandleDataReceived(SerialPort inPort, SerialPort outPort)
    {
        byte[] data = new byte[1];

        while (inPort.BytesToRead > 0)
        {
            // Read the data
            data[0] = (byte)inPort.ReadByte();

            // Write the data
            if (outPort.IsOpen)
            {
                outPort.Write(data, 0, 1);
            }
        }
    }

このコードは、発信 COM ポートが着信 COM ポートよりも高いボー レートで動作している限り、正常に機能しました。着信 COM ポートが発信 COM ポートよりも高速である場合、データが欠落し始めました。次のようにコードを修正する必要がありました。

    private void HandleDataReceived(SerialPort inPort, SerialPort outPort)
    {
        byte[] data = new byte[1];

        while (inPort.BytesToRead > 0)
        {
            // Read the data
            data[0] = (byte)inPort.ReadByte();

            // Write the data
            if (outPort.IsOpen)
            {
                outPort.Write(data, 0, 1);
                while (outPort.BytesToWrite > 0);  //<-- Change to fix problem
            }
        }
    }

なぜその修正が必要なのかわかりません。私は C# を初めて使用するので (これが初めてのプログラムです)、何か足りないものがあるのではないかと考えています。SerialPort のデフォルトは 2048 バイトの書き込みバッファで、コマンドは 10 バイト未満です。書き込みバッファーには、低速の COM ポートにデータを書き込むことができるようになるまで、データをバッファーする機能が必要です。

要約すると、COM X でデータを受信し、そのデータを COM Y に書き込んでいます。COM X は、COM Y よりも高速なボー レートで接続されています。書き込みバッファのバッファリングでこの違いが処理されないのはなぜですか? データの損失を避けるために書き込みバッファが空になるのを待つ必要があるように見えるのはなぜですか?

ありがとう!

* アップデート *

前述のように、このコードは、大規模および/または高速の着信データ転送で非常に簡単にオーバーフロー状態に陥る可能性があります。データ ストリームについてもっと書くべきでした。10 Hz で < 10 バイトのコマンド (< 10 バイトの応答) を期待しています。さらに、最初のコマンドで失敗が見られます。

したがって、このコードがスケーリングされておらず、最適ではないことはわかっていますが、なぜ 2 ~ 4K の読み取り/書き込みバッファーが最初のコマンドを処理できなかったのか疑問に思っています。1バイトのデータの書き込みにバグがあるのか​​ 、理解できないイベントハンドラーにバグがあるのか​​ 疑問に思っています。ありがとう。

* アップデート *

失敗の例を次に示します。

私のコマンドが 4 バイトだとしましょう: 0x01 0x02 0x3 0x4。COM X 上のデバイスがコマンドを送信します。C# プログラムが 4 バイトを受信し、COM Y 上のデバイスに送信していることがわかります。COM Y 上のデバイスは、0x01 0x03 の 2 バイトを受信します。COM Y のデバイスが信頼できることはわかっているので、2 バイトがどのように削除されたのか疑問に思っています。

ところで、回答にコメントで返信する方がよいのか、それとも元の質問を編集し続けるべきなのか、誰か教えてもらえますか? どちらがより役に立ちますか?

4

2 に答える 2

2

あなたがやろうとしていることは、消防ホースから水を飲むことと同じです。水を保存するために受信バッファーに依存しています。誰かが蛇口をオフにしないと、水は長くは続きません。あなたの回避策では、受信バッファが静かにオーバーフローすることを確認しています。おそらく ErrorReceived イベントを実装していません。

これを機能させるには、バッファがいっぱいになったときに送信を停止するように入力デバイスに指示する必要があります。これを行うには、Handshake プロパティを設定します。最初に Handshake.RequestToSend に設定します。次に XOnXOff を使用します。ハンドシェイク信号を適切に使用するかどうかは、デバイスによって異なります。

これをもう少し効率的にするには、Read() メソッドを使用します。


わかりました、消防ホースではありません。他に考えられる可能性は 1 つだけです。初期の UART チップ設計でよくある問題で、1 バイトしか格納できないオンチップ受信バッファがありました。次のバイトが到着する前に、割り込みサービスルーチンがそのバイトを読み取る必要がありました。ISR の速度が十分でない場合、チップは SerialError.Overrun 状態をオンにし、バイトは取り返しのつかないほど失われます。

この問題の回避策は、送信された各バイト間に人為的に遅延を入れて、デバイスの ISR がバイトを読み取るためにより多くの時間を与えることでした。これは、副作用として、回避策のコードが行うことです。

最新のチップ設計には、少なくとも 8 バイトの深さの FIFO バッファがあります。これに何らかの真実がある場合、ボーレートを下げると問題が解消されるはずです。また、ReadByte() の代わりに Read() を使用すると、Write() 呼び出しが一度に複数のバイトを送信できるようになり、文字間の遅延がなくなるため、問題が悪化するはずです。明確にするために、私は出力デバイスについて話しています。

于 2010-03-22T22:06:47.573 に答える
0

outPort.WriteBufferSize送信する予定の最大バッファよりも大きいことを確認する必要があります。また、ループ内で and を呼び出すReadByteWriteByte、通常は遅くなります。ハンドラーを次のように変更した場合:

int NumBytes = 20; //or whatever makes sense
byte[] data = new byte[NumBytes];

while (inPort.BytesToRead > 0)
{
    // Read as much data as possible at once
    count = inPort.Read(data, 0, min(NumBytes, inPort.BytesToRead));

    // Write the data
    if (outPort.IsOpen)
    {
        outPort.Write(data, 0, count);
    }
}

これにより、オーバーヘッドが削減され、役立つはずです。その後、書き込みバッファーは (うまくいけば) 期待どおりにタイミングを処理します。

于 2010-03-22T21:57:12.420 に答える