トップ回答者
serialportのDataReceivedイベントのデータ取りこぼしについて

質問
-
初めまして。
現在、Visual Studio 2012においてC#でマイコンからデータを受信するプログラムを作成しています。
一回に受信するデータセットは2つあり、一つ目は300byte程度なのですが、その直後に2つ目の小さなデータ(10byte程度)
が来た場合にデータの取りこぼしが発生してしまいます。
具体的にはデータの受信イベントが発生したら、以下のようにしてイベントハンドラを発生させています。
serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
その後、port.Read()を使用してデータをBufferに保存しておくのですが、小さいデータのみ
Bufferに保存されないという状況になっています。
なお、serialPortのReadBufferSizeはデータセットよりも十分に大きく取ってあります。
また、マイコン側の方の問題かと思いましたが、他のプログラム(TeraTerm)などでは正常に受信していることが確認できました。以上、ご教授のほどよろしくお願い致します。
回答
-
Data1は終端がCRなのか読み取れませんが、どちらなのでしょう?
Data1とData2が両方ともCRで終端されてるのであれば、単にData2として処理すべき部分を間違って捨てている可能性が高いです。Data1と間違えてチェックサムを計算してしまい、チェックサムが合わなくて捨てているかもしれません。
Data1がCR以外で終端されているのであれば、単純にCRを見落としているだけかもしれません。受信バイトにCRが来ているかを判定する処理をSerialPort_DataReceivedイベントおよびデータチェックに挿入し、ブレークポイントを置くなどして調べてみてください。
#Data1がCR以外で終端され、かつData1本文にCRを含む場合、逆にData2と誤認する可能性もありますけどね。データチェックを別スレッドで行っているようですが、そのデータチェックを行っている間にも受信イベントは引き続き発生します。チェックしている間にData2の先端文字コードを受信して、書き込み位置が進んでいるのに気付かずに先端文字が見つからなくてData2と判定されない可能性があります。SerialPort_DataReceivedイベントおよびデータチェックに終端のCRのチェックと同様に先端文字が来ているかの判定を入れて調べてください。
マイコン側が変更できるならData2だけを流すようにして受信バイトがどうなっているかを確認するのも手です。Data2しか来ないとわかっているならCRが来た時点でブレークさせて、ステップ実行させればどこで誤判定しているかが分かるのではないでしょうか。
なんにせよ、バイトデータとしての受信までは成功しているので、その後の受信処理かチェック処理が間違っている事だけは確かです。コードをよく見なおしてください。
上記を調べてもなお原因わからないというのであれば、通信フォーマットと受信処理およびデータチェックの判定部のコードを提示してもらえないと、これ以上の助言は行うことはできません。個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
すべての返信
-
提示されている情報のみから可能性として考えられることは
- Data1とData2の終端文字が異なるのにData1の終端文字で待ち続けている。
- Data1を受信した後にマイコンに何らかの送信処理を行って待ち状態になっていたり、ハンドシェイクの解除を忘れている。
- Data1を受信した後に何らかの処理を行ってからバッファをクリアしているが、その処理中に受信したData2の部分まで消してしまっている。
- 間違ってDataReceivedイベントを解除してしまっている。
- SerialPort_DataReceivedを抜けずに次のイベントを待とうとしている。
- Data2を受信できているけど誤判定をしてData2を捨ててしまっている。
ですかね。
原因を特定するには情報が足りていないので、もう少し詳しく現状の説明が必要になります。
- System.IO.Ports.SerialPortの各プロパティはどうなっていますか?初期値から変更している部分を提示してください。
- Data1およびData2の終端と判断できるもの何ですか?カンマ,CRLF,ETXそれとも固定文字数やタイミングで判定ですか?マイコンから送り出しているデータのフォーマットを提示してください。
- Data1を受信し終わってからDataReceivedイベントは発生が続きますか?
- Data1とData2の受信バッファは共有していますか?それとも別々に用意していますか?
- SerialPort_DataReceivedでの処理をできるだけ提示してください。(返信時の入力で並んでいるボタンにコードを挿入する機能があります)
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
返信有難うございます。
まず、SerialPortの各プロパティはCOM,Baudrate以外はデフォルトのままです。(パリティ無,ReceivedByteThreshold=1,RTS&DTR=Falseなど)
次に、データ1の識別にはチェックサムを導入しているのでその値で比較をしており、データ2に関しては先端文字コード(固定)と改行コード(CR)でチェックを行っています。
また、記述し忘れて申し訳ないのですが、一回の受信イベントでデータが同時に二個来るのではなく、一個のみです。(どちらが先となるのかは不定)
更に、Data1とData2のバッファは共通となっており、リングバッファを採用しています。
プログラムの流れは概ね以下のようになっています。データ受信→リングバッファにfor文で代入→データチェック(別スレッド)→データが正しければ、データをフォームに表示(Delegate+Invoke使用)
なお、データセットが1のみの場合は特に問題なく処理が行えます。
以上、簡潔ではありますがよろしくお願い致します。- 編集済み K.Arche 2014年4月12日 8:24
-
Data1は終端がCRなのか読み取れませんが、どちらなのでしょう?
Data1とData2が両方ともCRで終端されてるのであれば、単にData2として処理すべき部分を間違って捨てている可能性が高いです。Data1と間違えてチェックサムを計算してしまい、チェックサムが合わなくて捨てているかもしれません。
Data1がCR以外で終端されているのであれば、単純にCRを見落としているだけかもしれません。受信バイトにCRが来ているかを判定する処理をSerialPort_DataReceivedイベントおよびデータチェックに挿入し、ブレークポイントを置くなどして調べてみてください。
#Data1がCR以外で終端され、かつData1本文にCRを含む場合、逆にData2と誤認する可能性もありますけどね。データチェックを別スレッドで行っているようですが、そのデータチェックを行っている間にも受信イベントは引き続き発生します。チェックしている間にData2の先端文字コードを受信して、書き込み位置が進んでいるのに気付かずに先端文字が見つからなくてData2と判定されない可能性があります。SerialPort_DataReceivedイベントおよびデータチェックに終端のCRのチェックと同様に先端文字が来ているかの判定を入れて調べてください。
マイコン側が変更できるならData2だけを流すようにして受信バイトがどうなっているかを確認するのも手です。Data2しか来ないとわかっているならCRが来た時点でブレークさせて、ステップ実行させればどこで誤判定しているかが分かるのではないでしょうか。
なんにせよ、バイトデータとしての受信までは成功しているので、その後の受信処理かチェック処理が間違っている事だけは確かです。コードをよく見なおしてください。
上記を調べてもなお原因わからないというのであれば、通信フォーマットと受信処理およびデータチェックの判定部のコードを提示してもらえないと、これ以上の助言は行うことはできません。個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)