tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルVB2010のSerialportの受信イベントについて
記事No10621
投稿日: 2011/11/24(Thu) 16:51
投稿者TANTAN
お世話になります。VB歴1年半のTANTANといいます。
VB2010のSerialportの受信イベントについての質問です。

今、VB2010の[System.IO.Ports.SerialPort]を使用して
バイナリ通信のRAMモニタソフトを設計しています。
基板とPCを繋げて、PCから「コマンド+アドレス+データ+チェックサム」を
送信すると、基板から「コマンド+アドレス+データ+チェックサム」がPCに
返されて、それのデータを表示するソフトを作ろうとしています。

環境は、
OS:XP
VB構成:VB2010ExpressEdition,日本語ServicePack1,日本語用の修正プログラム
SerialPort.BaudRate:38400bts
SerialPort.Parity:Even
(後は初期設定)
です。

現象を説明しますと、PC側から「メモリ読み出しコマンド」を[.Write]命令で送り
[SerialPort.ReceivedBytesThreshold=1]を設定します。
そして、発生した[Serialport]の[DataReceived]イベントの最初に、
[.Read]命令で、基板から返されたデータを読み出そうとするのですが、
特定のアドレスでのRead命令でエラーが起こります。
「IOExeptionはハンドルされませんでした。
 スレッドの終了またはアプリケーションの要求によって、I/O 処理は中止されました。」
 というエラーです。
自分でした対策として、有効だったのが
 [Read命令の前にDo While文でSerialport.BytestoRead<>0 になるまで待ってから
 Read命令に進む]
でして、今はとりあえずそれを使っています。(他にRead命令の前で100ms待たせると
エラーが出ずに実行できました。)

そして、質問なのですが、上の対策から推測するに、
「特定のアドレスにWriteで送ったコマンドのレスポンスが遅れ、受信イベントが発生した時点では
まだRead命令で読み込める状態ではなかったのでエラーが出る」
という状況かと思われますが、自分が知りたいのが

「アドレスによって、受信イベント発生時点で読み込めるデータ量やレスポンス速度に差が出るのか?」
ということです。

どなたか、アドバイスできる方がいましたら、レスの方お願いします。

[ツリー表示へ]
タイトルRe: VB2010のSerialportの受信イベントについて
記事No10622
投稿日: 2011/11/24(Thu) 18:14
投稿者オショウ
> どなたか、アドバイスできる方がいましたら、レスの方お願いします。

  シリアル通信の仕様を理解されていませんネ!
  データの送受信以外に制御線の変化でもイベントは発生します。

  フロー制御なしにすると、制御線の変化によるイベントは発生
  しなくなりますが・・・

  受信イベントの先頭で必ず『データ受信のイベント』である事
  を確認し、尚且つ受信バッファにデータがあることを条件にし
  て、Readすると言う流れを作って下さい。

以上。

[ツリー表示へ]
タイトルRe^2: VB2010のSerialportの受信イベントについて
記事No10623
投稿日: 2011/11/24(Thu) 18:56
投稿者TANTAN
>   フロー制御なしにすると、制御線の変化によるイベントは発生
>   しなくなりますが・・・
>
>   受信イベントの先頭で必ず『データ受信のイベント』である事
>   を確認し、尚且つ受信バッファにデータがあることを条件にし
>   て、Readすると言う流れを作って下さい。
>
オショウさん、回答ありがとうございます。

フロー制御に関しては、「制御無し」で作っています。
イベントの確認はしておりませんでしたので、また調べたいと思います。
データの有無の確認については、SerialPort.BytestoReadで1バイト以上あることを
確認してからReadの処理に入っていくようにしています。

自分の考えでは、ReceivedBytesThresholdを指定して、受信イベントが起こりReadすれば
ReceivedBytesThreshold分のReadは保障されていると思っていたのですが、
今回、特定のアドレスに対するRead命令が、途中までしか読み込んでくれなくて、後半は
全て配列初期値の「0」のままになってしまいシステムが動かなくなったりしていました。

受信イベントが発生しても、すぐに全てのデータは読めないということでしょうか?

[ツリー表示へ]
タイトルRe^3: VB2010のSerialportの受信イベントについて
記事No10624
投稿日: 2011/11/24(Thu) 22:26
投稿者オショウ
> 受信イベントが発生しても、すぐに全てのデータは読めないということでしょうか?

  理論的には、イベントが発生する条件は、受信しないと発生しない
  ので、ありえないのですが、PCのスペックが低い場合、イベント
  の先頭で読み出しを行うと、『受信バイトがゼロ』となる事象は、
  私も経験があります。

  PCのスペックが十分にあった場合は・・・どこかにプログラム的
  な問題があって、正常に動作していないことがあります。

  受信データの区切り文字に何か固定のコード(デリミタ)になるも
  のの通信の場合は(テキスト形式でもバイナリ形式でも)、そのコ
  ードを受信するまで待ち合わせることができます。

  無い場合は、確実に1バイト受信方式で読み貯めてから一気に処理
  を行うことになるでしょう。

※ デリミタコードがあった場合、.ReadTo(デリミタコード)とできます。

※ 簡単に書けば・・・
    Public Overridable Sub OnReceive(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)

        Dim dev As SerialPort
        Dim sz As String

        dev = DirectCast(sender, SerialPort)

        If e.EventType = SerialData.Chars Then
            sz = devSerial.ReadTo(DATA_END_CODE)
            If sz <> String.Empty Then
                RaiseEvent ReceiveData(sz)
            End If
        End If

    End Sub

  コードの説明はしません。
  使い方は推理してください。

以上。参考まで

[ツリー表示へ]
タイトルRe^4: VB2010のSerialportの受信イベントについて
記事No10625
投稿日: 2011/11/25(Fri) 00:34
投稿者TANTAN
オショウさん、回答していただいてありがとうございます

>   理論的には、イベントが発生する条件は、受信しないと発生しない
>   ので、ありえないのですが、PCのスペックが低い場合、イベント
>   の先頭で読み出しを行うと、『受信バイトがゼロ』となる事象は、
>   私も経験があります。
>
>   PCのスペックが十分にあった場合は・・・どこかにプログラム的
>   な問題があって、正常に動作していないことがあります。
>
 当方、VB2010での通信プログラムに関わるのは初めてでして、今回の
相談内容もソフトが悪いのか、システム的にしょうがないのかの判断が
つかず困っていました。オショウさんのように実体験に基づいた話が聞けて
とても助かります。
 PCのスペックは標準以上なので、読めない原因はプログラムにあるかと
思われるので、プログラムの無駄を省くか、Read命令前に、
  
  Do while serialport.BytetoRead <> 0
  Loop

を書くなどして、確実に受信するプログラム作りを見直してみようと思います。

>   受信データの区切り文字に何か固定のコード(デリミタ)になるも
>   のの通信の場合は(テキスト形式でもバイナリ形式でも)、そのコ
>   ードを受信するまで待ち合わせることができます。
>
>   無い場合は、確実に1バイト受信方式で読み貯めてから一気に処理
>   を行うことになるでしょう。

今回、区切り文字が無い仕様でして(条件に書くのを忘れてしまいました、すみません)
1文字めのコマンド文字からデータの長さを判断して、再度受信イベントを起こす
という形式で書いています。
1バイト受信方式で読み貯めるというのは自分の考えにはありませんでした。
わざわざコードまで書いていただき本当にありがとうございます。
(受信イベントが起こった時に、その受信したデータを区切り文字まで読み込んだ事と
データの有無を確認して、完全な受信データを渡してくれるコードでしょうか。また
手元に環境があるときに考えさせていただきます。)

今回の件に関して、体験談含めて有効なアドバイスももらえたので
これらを参考にさせてもらいながら進めてみようと思います。
また、新たに相談・質問が出た場合はよろしくお願いします。

[ツリー表示へ]
タイトルRe^5: VB2010のSerialportの受信イベントについて
記事No10626
投稿日: 2011/11/25(Fri) 01:33
投稿者オショウ
>   Do while serialport.BytetoRead <> 0
>   Loop

  このコードはよろしくないので、やめるべきです。

  If serialport.ByteToRead <> 0 Then
    ' 受信処理
  End If
   ' 抜ける・・・

  受信バッファにデータが入って、読みだされない場合、イベントは
  通常出続けるはずなんですが・・・

※ そのシリアルポートは、PC本体ですか?
  拡張ボード? USB変換アダプタ?
  デバイスドライバーの都合で、適切な受信コードを書いてやる必要
  があります。またドライバー側の設定もできるものであれば、適切
  に動作するように設定変更するべきです。

以上。参考まで

[ツリー表示へ]
タイトルRe^6: VB2010のSerialportの受信イベントについて
記事No10627
投稿日: 2011/11/25(Fri) 10:31
投稿者TANTAN
オショウさん、回答ありがとうございます。

> >   Do while serialport.BytetoRead <> 0
> >   Loop
>
>   このコードはよろしくないので、やめるべきです。

今、中に仕込んだカウンタで検証してみたら、凄まじいLoop回数が返ってきて
よろしくない理由が良く分かりました。
>
>   If serialport.ByteToRead <> 0 Then
>     ' 受信処理
>   End If
>    ' 抜ける・・・
>
>   受信バッファにデータが入って、読みだされない場合、イベントは
>   通常出続けるはずなんですが・・・

上のコードを入れたところ、1バイト目の受信で失敗することなく
確実にRead命令が実施できました。ありがとうございます。
この後、コマンド判断をしてから全体のデータ長を設定して、1バイトずつ
Readしていくコードを書こうと思います。

> ※ そのシリアルポートは、PC本体ですか?
>   拡張ボード? USB変換アダプタ?
>   デバイスドライバーの都合で、適切な受信コードを書いてやる必要
>   があります。またドライバー側の設定もできるものであれば、適切
>   に動作するように設定変更するべきです。

シリアルポートはPC本体の物を使用しています。
デバイスドライバー毎の適切な通信というのを、考えたことが無かったので
仕様に合うように設定などを変えることが出来ないか、検討してみます。

[ツリー表示へ]