
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
VB.netで、シリアル通信のタイムアウト処理について
Visual Basic(VBA)
-
5
Linuxでのシリアル通信についてですが、受信のときにデータがずれた状態で送られてくることがあります
C言語・C++・C#
-
6
FORMが開いているかどうかの確認方法
Visual Basic(VBA)
-
7
シリアル通信の受信待ちについて
C言語・C++・C#
-
8
C#のシリアル通信プログラムで文字化け
C言語・C++・C#
-
9
別のフォームで記述している関数を実行するには?C#
C言語・C++・C#
-
10
C# ソケット通信でデータ受信時の欠損について
C言語・C++・C#
-
11
C#で通信処理。応答がない場合、すぐエラーにしたい
その他(プログラミング・Web制作)
-
12
CloseとDisposeの違い
Visual Basic(VBA)
-
13
VB.NET(2005)のSerialPort" RTSラインを制御"
Visual Basic(VBA)
-
14
シリアル通信で0x00を送信したいのですが。
C言語・C++・C#
-
15
インスタンス参照でアクセスできない。代わりに型名?
C言語・C++・C#
-
16
シリアル通信 大きいサイズの受信処理
C言語・C++・C#
-
17
Teraterm で、「シリアル」の方を選択出来ません。
その他(ソフトウェア)
-
18
win10で、正確な待ち時間の作り方
C言語・C++・C#
-
19
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
20
メッセージボックスを大きくする方法
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
【CAsyncSocket::OnReceive()呼...
-
WriteFile()でのデータ送信がで...
-
socket: recvはいつ,どれだけ...
-
シリアル通信ができません
-
winsockでソケット通信の開発を...
-
winsockの動作について。
-
シリアル通信 大きいサイズの...
-
winsock recvでデータの取得方法
-
Macターミナルで実行中のプログ...
-
powershell を使いカレントディ...
-
バックグラウンドのプロセスの...
-
パソコンの演算速度について
-
エクセルVBA 大容量CSVファイル...
-
VBSの処理中一旦処理を止めて再...
-
【C言語】再帰が時間がかかる...
-
子プロセスの状態を親プロセス...
-
keycodeについて
-
sendkeysにてALT+CTRL+INSERTを...
-
マイコンからプログラムを読み...
-
スーパーのレジで並んでいたら...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
winsockでソケット通信の開発を...
-
socket: recvはいつ,どれだけ...
-
「スイッチングハブのバッファ...
-
VB2005でWin32APIを用いてRS-23...
-
シリアル通信エラー
-
シリアル通信の出力バッファと...
-
バイナリデータ受信時のデータ順
-
WinsockAPIのrecvfromの受信デ...
-
SerialPortのDataReceivedイベ...
-
再現性の無いバグ
-
rs232cでの受信データ(mscomm)...
-
C#で通信処理。応答がない場合...
-
Linuxでのシリアル通信について...
-
WriteFile()でのデータ送信がで...
-
【CAsyncSocket::OnReceive()呼...
-
UDP処理のエラーについて
-
recv関数の受信結果について
-
ReadFile(GPSとの通信)Win7で...
-
VC++ HttpOpenRequest() 正し...
おすすめ情報