
Visualstudio 2013 を使用して C# で開発を行っています。
SerialPort Classを使用してデータの送受信をするプログラムを作成しているのですが、
非同期でデータを受信する際にどうしてもうまくデータを取得出来ません。
5Byteのデータは正常に取得できるのですが、
その直後にくる40Byteのデータは、真ん中あたりの10数Byteや最後の10数Byteしか取れません。
serialPort.DataReceived に登録したイベント関数の中身です。
--------------------------------------------------------------------------------------
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
bytesRead = 0;
// Initialize a buffer to hold the received data
byte[] buffer = new byte[this.serialPort.ReadBufferSize];
try
{
bytesRead = this.serialPort.Read(buffer, 0, buffer.Length);
if (true == serialPort.IsOpen)
{
serialPort.DiscardInBuffer();//受信バッファをクリアする
}
}
catch (Exception ex)
{
DataLog.Exception(ex);
}
//派生クラス用の処理
DeviceClassEventArgs _DeviceClassEventArgs = new DeviceClassEventArgs(buffer, bytesRead);
DeviceClassEvent(this, _DeviceClassEventArgs);
}
--------------------------------------------------------------------------------------
ネットの情報を参考に、
ReceivedBytesThreshold の値を期待するデータ量に逐一変えることで
とりあえず正常に取ることが出来たのですが、これでいいのでしょうか?
期待するデータ量がわからなかった場合は使えないのかなとも思います。
データが欠損してしまう理由、
上記の対処法以外の一般的な対処法など有りましたら教えて下さい。
その他参考になるページ等ありましたら教えていただけると大変助かります。
No.3ベストアンサー
- 回答日時:
DataReceivedイベントが発生したときでも、
シリアルポートへの受信はまだ継続している可能性があるので
不用意にバッファクリアしてはいけない。
非同期の受信処理は、何かと難しいのです。
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
bytesRead = 0;
// Initialize a buffer to hold the received data
byte[] buffer = new byte[this.serialPort.ReadBufferSize];
try
{
//bytesRead = this.serialPort.Read(buffer, 0, buffer.Length);
//if (true == serialPort.IsOpen)
//{
// serialPort.DiscardInBuffer();//受信バッファをクリアする
//}
// 受信バッファにデータがなくなるまで繰り返し読込む
while (true)
{
if (0 == serialPort.BytesToRead)
{
break;
}
buffer[bytesRead] = (byte)serialPort.ReadByte();
bytesRead++;
System.Threading.Thread.Sleep(0);
// シリアルポートの受信バッファには、
// ・必要なブロックの途中から受信している。
// ・次のブロックの先頭部分も受信されている。
// 可能性があるので、ここで必要なブロックだけRead()できたことを確認する。
if (必要なブロックが正常に読めたか確認する関数())
{
break;
}
}
}
catch (Exception ex)
{
DataLog.Exception(ex);
}
//派生クラス用の処理
DeviceClassEventArgs _DeviceClassEventArgs = new DeviceClassEventArgs(buffer, bytesRead);
DeviceClassEvent(this, _DeviceClassEventArgs);
}
>不用意にバッファクリアしてはいけない。
なるほど。確かにそうですね。
なにが起こっているのかわからなかったのですがやっと理解出来ました。
ありがとうございます。
No.4
- 回答日時:
最初に _serialPort_DataReceived 関数で 5 Byte 読んで
その後 _serialPort_DataReceived 関数で 40 Byte を読んだら、
途中からしか取れなかった。 関数の中には、「通信ポートを
オープンしてるなら受信バッファをクリアする」
if (true == serialPort.IsOpen)
{
serialPort.DiscardInBuffer();//受信バッファをクリアする
}
という処理が入っているのですから当然そうなるのではないですか?
読込の関数を読んだ時点からデータの受信を開始するとした為、
それまで受信していたデータを捨ててまっさらな状態にする為
受信バッファをクリアしてるのですから
そう考えれば解決方法は簡単で
受信バッファをクリアするの部分を受信バッファにある分、
全て別のバッファに読む様に修正して
その別のバッファの中身を捨てるか、この後の本来の受信処理と
つなげて処理するかを、通信フロー等を考慮しながら決めて
通信プログラムを作成します
>読込の関数を読んだ時点からデータの受信を開始するとした為、
それまで受信していたデータを捨ててまっさらな状態にする為
受信バッファをクリアしてるのですから
なるほど。確かにそうですね。
なにが起こっているのかわからなかったのですがやっと理解出来ました。
ありがとうございます
No.2
- 回答日時:
一般的な対処法は意味を持ちません。
通信相手がどのような機器でどのようなデータをどのようなプロトコルで通信するのか、相手側のプログラムや設定を変更できるか等で全く変わってしまいます。
No.1
- 回答日時:
>データが欠損してしまう理由、
>上記の対処法以外の一般的な対処法など有りましたら教えて下さい。
1.フロー制御を行う
2.ボーレートを下げる 等が一般的かと思います
場合によってはキャラクタ間にウエイト入れたり(これやると当然レスポンスは落ちます)
1を行うときは
信号線でのフロー制御を行う場合ケーブルも
きちんと制御線に対応していることが条件となります
キャラクタベースのフロー制御(XON/XOFF)はやり取りしてるデータによっては
使えない場合があります(バイナリデータやり取りする場合などは無理)
とりあえず送信側でデータが落ちてるのか受信側で
データ落ちしてるのかを確認するのが先ではないかと思います
オーバランとかアンダーランとかのステータス確認してみてください
あくまで参考までに
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
SerialPortのDataReceivedイベントについて
Visual Basic(VBA)
-
シリアル通信の出力バッファと送信完了イベントについて
C言語・C++・C#
-
ManagementClassが見つからない。
C言語・C++・C#
-
-
4
Linuxでのシリアル通信についてですが、受信のときにデータがずれた状態で送られてくることがあります
C言語・C++・C#
-
5
VB.netで、シリアル通信のタイムアウト処理について
Visual Basic(VBA)
-
6
FORMが開いているかどうかの確認方法
Visual Basic(VBA)
-
7
C#のシリアル通信プログラムで文字化け
C言語・C++・C#
-
8
CloseとDisposeの違い
Visual Basic(VBA)
-
9
シリアル通信の受信待ちについて
C言語・C++・C#
-
10
シリアル通信でのデータ取りこぼし
Visual Basic(VBA)
-
11
別のフォームで記述している関数を実行するには?C#
C言語・C++・C#
-
12
C# ソケット通信でデータ受信時の欠損について
C言語・C++・C#
-
13
シリアル通信で0x00を送信したいのですが。
C言語・C++・C#
-
14
NetworkStreamからのRead()で、処理が止まる(C#)
C言語・C++・C#
-
15
C#で通信処理。応答がない場合、すぐエラーにしたい
その他(プログラミング・Web制作)
-
16
TextBoxに文字を書いても表示されない
Visual Basic(VBA)
-
17
C#にてCTI。RS232Cの受信と送信について。
その他(プログラミング・Web制作)
-
18
VB.NET(2005)のSerialPort" RTSラインを制御"
Visual Basic(VBA)
-
19
シリアル通信でのデータ受信
C言語・C++・C#
-
20
インスタンス参照でアクセスできない。代わりに型名?
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
winsockでソケット通信の開発を...
-
SerialPortのDataReceivedイベ...
-
Linuxでのシリアル通信について...
-
「スイッチングハブのバッファ...
-
popen実行時にバッファが空の場合
-
UDP処理のエラーについて
-
winsockの動作について。
-
VB2010 シリアル受信した情報を...
-
visual c# 2010 シリアル通信ア...
-
ftplibのエラー処理
-
Macターミナルで実行中のプログ...
-
プログラム上のCPU稼働率低減に...
-
プロセスIDの取得方法について
-
VBSの処理中一旦処理を止めて再...
-
メモリが不足しています(VBA)
-
バックグラウンドのプロセスの...
-
H8 マイコン セクションの設...
-
インスタンスハンドルは何の役...
-
ACCESS側からEXCELの書式を設定...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
「スイッチングハブのバッファ...
-
WriteFile()でのデータ送信がで...
-
socket: recvはいつ,どれだけ...
-
winsockでソケット通信の開発を...
-
RS-232Cでバイナリデータを受信...
-
SerialPortのDataReceivedイベ...
-
シリアル通信エラー
-
C#で通信処理。応答がない場合...
-
Linuxでのシリアル通信について...
-
シリアル通信の出力バッファと...
-
バイナリデータ受信時のデータ順
-
ReadFileについて
-
トラックバック機能を作りたい
-
ソケット通信内 read関数について
-
recv関数の受信結果について
-
ReadFile(GPSとの通信)Win7で...
-
visual c# 2010 シリアル通信ア...
-
WinsockAPIのrecvfromの受信デ...
-
popen実行時にバッファが空の場合
おすすめ情報