トップ回答者
シリアル通信で16進数の"1A"を受信すると、その後のデータが受信できない

質問
-
いろいろ勉強して、トライして、なんとかシリアル通信ができるようになりましたが、
バイナリの受信で、データの途中に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.DataReceivedDim 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 SubPrivate Sub updateTextBox(ByVal INDATA() As Byte)
以下省略INDATA()の中を解析して、表示や制御をしています。
INDATA()に1Aが有ると、その3バイト後以降が0になっているようです。
アドバイスをよろしくお願いします。
回答
すべての返信
-
外池様 返信ありがとうございます。遅くなり申し訳ありません。
もう少し、状況を説明します。
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ですが、確認できていません。申し訳ありません。
-
外池です。
うーん、SerialPort.BytesToReadを調べることは基本だと思うので、是非、調べてください。
ひとつ原則的な考え方として、11バイトが一度に入ってくるとは限らない、ということです。8バイトと3バイトと2回にわけてDataReceivedイベントが発生することも十分にあり得ます。受信したデータが全部で11バイトに達するまで待つような工夫を試してみてはいかがでしょうか?
あと、他の記事でも話題になりましたが、SerialPortをOpenしていないときでも、OS側ではSerialPortに受信したデータを貯えたままになっていることもあります。接続されている機器と「通信をスタートしなおす」ためにも、一種のリセット動作が必要と思います。ですので、
-
SerialPort.BytesToReadがゼロになるまでクズ受信データを掃きだす操作をする。
-
その上で7バイトのデータをPCから送信する。
-
次に11バイトのデータを取り込むまで受信操作を繰り返す
という感じになると思いますが・・・。どこまで上手く行ってて、どこでつまずいてます?
-
-
どうもありがとうございます。
なんとなく、「1A」をEnd of fileとして認識して、DataReceivedイベントが発生。
そこで、読み出すと8バイトしかない。という感じですかね。
今回の問題になっている所は、11バイトの受信ですが、他にもこのルーチンを使っているので、
場合分けが必要になってきます。少し時間をください。試してみます。
それと、
「リセット動作の件」については、シリアルポートをクローズする時に、バッファをクリアしています。
無くても変わらなかったのですが、ノイズで失敗した時に良いかなという感じで付けています。
(効果は実感できていません。)