1

Visual Studio 2013 .NET Framework 4.5 でシリアル ポートのバイト処理を行っています。着信パケット サイズの変化に問題が発生しています。ReceivedByteThreshold を対応するパケット サイズに調整しようとすると、しきい値が受信パケット サイズよりも低く設定されている場合にデータ受信イベントが複数回トリガーされ、しきい値がパケット サイズよりも大きい場合はアクティブになりません。この問題に対処するためにいくつかの異なる方法を試しましたが、どれも完全に機能していないようです.

    private: System::Void serialPort1_DataReceived(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^  e)
         {


             array<uint8_t>^ CS = gcnew array<uint8_t>(2);
             //Check InvokeRequired to prevent cross threading problem 
             if (textBox3->InvokeRequired) {
                 //Invoke delegate
                 textBox3->Invoke(
                     gcnew System::IO::Ports::SerialDataReceivedEventHandler(this, &MyForm::serialPort1_DataReceived),
                     gcnew array<System::Object^> { sender, e }
                 );
             }

             else
             {

                 //ASCII -> HEX Conversion
                 int numbytes = serialPort1->BytesToRead;
                 array<Byte>^ encodedBytes = gcnew array<Byte>(500);

                 serialPort1->Read(encodedBytes, 0, numbytes);

             }
         }

上記のコードは、しきい値が正確なパケット サイズに設定されている場合にのみ機能します。着信データの長さについてある程度の知識があるため、ボタン クリック イベントを使用して、発信バッファーに基づいてしきい値を変更しましたが、データはまだ正しく読み込まれていません。Readexisting() は完璧に機能しますが、8 ビット ASCII 文字をスキャンすると、「?」として表示されます。例のために。0xff.

誰かが同じ問題に遭遇したか、このしきい値の問題に対する解決策があるかどうか疑問に思っています.

よろしくお願いいたします。

よし

4

1 に答える 1

1

はい、ReceivedThreshold に依存すると、非常に脆弱なコードが生成されます。2 つの強力な障害モードがあります。明らかな 1 つは、前のコマンドへの応答が受信される前に、SerialPort.Write() を呼び出すコードでプロパティを設定した場合です。それを防ぐにはインターロックが必要ですが、あなたには何もありません。コードをフルスピードで実行するときではなく、デバッグするときに問題なく動作します。

明白でない障害モードは、DataReceived イベント ハンドラーの e.EventType プロパティです。イベント ハンドラーが SerialData.Chars に対して呼び出されたことを確認するには、これをチェックする必要があります。バイナリ データを転送するときにも SerialData.Eof に対して発生します。これは無視する必要があります。

インターロックには、少なくとも AutoResetEvent が必要であり、イベント ハンドラーでその Set() メソッドを呼び出します。Write() を呼び出すコードでその WaitOne() メソッドを呼び出す必要があるため、応答が受信されるまで進行できません。ここで、別の厄介な問題に遭遇します。Invoke() 呼び出しがデッドロックします。代わりに BeginInvoke() を呼び出して修正する必要があります。これは、Read() を呼び出した後でのみ行います。また、配列のコピーを渡す必要があるため、DataReceived が起動し続けたときに配列が変更されることはありません。

これをすべて正しく行うのは非常に困難です。中心的な問題は、受信側のコードだけでは、応答がいつ完全に受信されたかを判断できないことです。これにはprotocolが必要です。これは、応答がいつ完了したかをリーダーが把握できるように、応答バイトに十分な情報が含まれています。DataReceived イベントを完全に排除し、Write() を呼び出すコードがすぐに Read() を呼び出して応答を取得することで、先に進むことができます。これにより遅延が発生しますが、必要な WaitOne() 呼び出しから既にそれらを取得しています。

于 2013-11-06T12:28:28.870 に答える