none
シリアル通信で16進数の"1A"を受信すると、その後のデータが受信できない RRS feed

  • 質問

  • いろいろ勉強して、トライして、なんとかシリアル通信ができるようになりましたが、

    バイナリの受信で、データの途中に16進数の"1A"を受信すると、その2バイト後までは受信できるのですが、

    それ以降のデータが無くなってしまいします。(0になっているみたいです)

    16進数の"1A"は、コントロールコードのEOFの役目があるようですが、バイナリの受信では、00~FFまで

    何が来るのか分からないので、このままでは困ってしまいします。

    1Aの後2バイト受信しているので、文字列として扱われているようにも見えるのですが、

    何か対策方法はありませんか?

     

    以下に、ソースコードをあげます。

        Delegate Sub myDelegate(ByVal INDATA() As Byte)

     

        Private Sub DataReceived(ByVal sender As Object, _
              ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
              Handles SerialPort1.DataReceived

            Dim byteArray(1024) As Byte
            Dim add As New myDelegate(AddressOf updateTextBox)

            Try
                SerialPort1.Read(byteArray, 0, SerialPort1.BytesToRead)
            Catch ex As Exception
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub

        Private Sub updateTextBox(ByVal INDATA() As Byte)
        以下省略

    INDATA()の中を解析して、表示や制御をしています。

    INDATA()に1Aが有ると、その3バイト後以降が0になっているようです。

     

    アドバイスをよろしくお願いします。

     

     

    2008年11月27日 1:02

回答

  • 外池です。

     

    英語版のMSDNのには、もろ、該当するRemarkがありますね。「End of fileを受信するとDataReceivedイベントが発生するかもしれない。Bufferの中に何バイト入っていようが、ReceivedBytesThresholdにどのような値がセットしてあろうが」ということです。

     

    そんなわけで、希望のバイト数になるまで、引き続きDataReceivedイベントが発生するのを待つしかないでしょう。

     

     

    2008年11月28日 12:11

すべての返信

  • 外池と申します。少し状況のご説明を、整理と申しますか、補強していただけませんか?

    • 1Aを受信したとき、1A自身と引き続く2バイトのデータ(全部で3バイト)の並び方は、送信側のデータの該当部分と一致しているのでしょうか?
    • また、その時に、SerialPort.BytesToReadは何バイトを示しているのでしょう? 3バイトならあまり問題ないように思います。引き続き受信を待てば良いと思うのですが・・・・、
    • それとも、一度1Aを受信するとその後の受信が止まってしまいます?

     

    2008年11月27日 2:18
  • 外池様 返信ありがとうございます。遅くなり申し訳ありません。

     

    もう少し、状況を説明します。

    VBのソフトは、パソコン側にあり、通信相手はマイコンが搭載された装置(WindowsなどのOSは搭載されていま

    せん)になります。

    パソコン側から7バイトのデータを送ると、11バイトのデータを返信してきます。その11バイトの5バイト目

    と6バイト目は値が大きく変わるのですが、そこに「1A」が含まれる可能性があります。その後の7バイト目は

    「00」、8バイト目は「50~6F」、9バイト目は「50~6F」、10バイト目は「08」、11バイト目

    はチェックサムなので不定です。

    パソコンのソフトでは、初めにシリアルポートをオープンし、受信バイト数の値の

    SerialPort1.ReceivedBytesThreshold=11をセットして、7バイトのデータを送信します。その後、0.2秒待って

    、シリアルポートをクローズします。その後、0.1秒待って、再びシリアルポートをオープンという所に戻って

    、以下繰り返しています。

    毎回、シリアルポートをオープン/クローズを行なっているのは、ノイズなどが原因で、通信が止まってしまうた

    めです。

    上記の0.2秒待っている間に、装置から11バイトのデータが送られて来て、DataReceivedの割り込みが発生し

    て、SerialPort1.Readでデータを取り込んでいます。

     

    ご質問の6バイト目の「1A」の後の2バイトは、「00」「60ぐらい」で、オシロスコープで見て確認してい

    ます。また、それ以降11バイト目まで、すべて送られていることを確認しています。しかし、「1A」を受信し

    た時は、9~11バイト目のデータ(INDATA(8)~INDATA(10))がすべて「00」になっています。
    ここで、説明不足に気づきました。5バイト目に「1A」、6バイト目に「1A」以外を受信した場合でも、8バイト目まで

    受信できます。両方とも「1A」の場合も8バイト目まで受信できます。

     

    また、「1A」受信後も、以降の送信、受信はしています。

     

    SerialPort.BytesToReadですが、確認できていません。申し訳ありません。

    2008年11月28日 1:53
  • 外池です。

     

    うーん、SerialPort.BytesToReadを調べることは基本だと思うので、是非、調べてください。

     

    ひとつ原則的な考え方として、11バイトが一度に入ってくるとは限らない、ということです。8バイトと3バイトと2回にわけてDataReceivedイベントが発生することも十分にあり得ます。受信したデータが全部で11バイトに達するまで待つような工夫を試してみてはいかがでしょうか?

     

    あと、他の記事でも話題になりましたが、SerialPortをOpenしていないときでも、OS側ではSerialPortに受信したデータを貯えたままになっていることもあります。接続されている機器と「通信をスタートしなおす」ためにも、一種のリセット動作が必要と思います。ですので、

    • SerialPort.BytesToReadがゼロになるまでクズ受信データを掃きだす操作をする。
    • その上で7バイトのデータをPCから送信する。
    • 次に11バイトのデータを取り込むまで受信操作を繰り返す

    という感じになると思いますが・・・。どこまで上手く行ってて、どこでつまずいてます?

     

     

     

     

     

     

     

     

     

    2008年11月28日 2:25
  • どうもありがとうございます。

     

    なんとなく、「1A」をEnd of fileとして認識して、DataReceivedイベントが発生。

    そこで、読み出すと8バイトしかない。という感じですかね。

    今回の問題になっている所は、11バイトの受信ですが、他にもこのルーチンを使っているので、

    場合分けが必要になってきます。少し時間をください。試してみます。

     

    それと、

    「リセット動作の件」については、シリアルポートをクローズする時に、バッファをクリアしています。

    無くても変わらなかったのですが、ノイズで失敗した時に良いかなという感じで付けています。

    (効果は実感できていません。)

     

     

    2008年11月28日 7:56
  • 外池です。

     

    英語版のMSDNのには、もろ、該当するRemarkがありますね。「End of fileを受信するとDataReceivedイベントが発生するかもしれない。Bufferの中に何バイト入っていようが、ReceivedBytesThresholdにどのような値がセットしてあろうが」ということです。

     

    そんなわけで、希望のバイト数になるまで、引き続きDataReceivedイベントが発生するのを待つしかないでしょう。

     

     

    2008年11月28日 12:11
  • 外池さん どうもありがとうございます。

     

    「End of fileを受信するとDataReceivedイベントが発生するかもしれない。
    Bufferの中に何バイト入っていようが、ReceivedBytesThresholdに
    どのような値がセットしてあろうが」というのは、どうも正しいようです。

     

    DataReceivedイベントの中で、受信予定バイト数とSerialPort.BytesToReadを
    比較して、不足している時は待つようにしたら、11バイトの最後まで
    読めるようになりました。

     

    問題解決しました。ありがとうございます。

    2008年12月1日 0:48