シリアル通信エラーの原因と解決方法について

このQ&Aのポイント
  • VBのMSCommを使用してシリアル通信アプリを作成しましたが、WinMeのノートPCではデータ受信時にエラーが発生します。
  • エラーコード1006はポートオーバーランを意味し、FIFOバッファが一杯になりデータの一部が失われた可能性があります。
  • 受信バッファを低レベルに設定することで解決する可能性がありますが、現在の設定では問題が解消されていないため、他の解決策を模索しています。
回答を見る
  • ベストアンサー

シリアル通信エラー

VBのMSCommにてシリアル通信アプリを作成しました。 デスクトップPC(Win2000)では正常に動作するにも関わらず、 ノートPC(WinMe)ではデータ受信時にとりこぼしが発生する様です。 とりあえず、MSCommのOnCommイベントプロシージャ内でCommEventプロパティにて エラーコードを引っ掛けると、1006(ポート オーバーランです。ハードウェアから 1 文字が読み取られる前に、次の文字が受信されたため、先の文字は失われました。)というエラーが返却されます。 デスクトップPCでは何日か継続して通信させておいても、全くこのエラーが出ないのに ノートPCでは数秒~数分で頻繁に発生します。 このエラーの意味について調査したのですが、様々なHPを見ると、FIFOバッファ(通常16バイト)のエリアが一杯になり、前にかかれていたデータが上書き されたという事ではないかという所に辿り着きました。そこで、デバイスのポート設定の詳細 にて受信バッファを低レベル(1バイト受信毎にCPU割り込みを発生)にする事により、なるべく FIFOバッファの余裕を持たせる設定にすれば、問題は解決あるいは頻度の減少を期待出きる と思い、設定したのですが、結果は全く変わりませんでした。そこで質問です。 1)このエラーの意味は本当にFIFOバッファのオーバーランなのでしょうか。 2)もし、そうであるならば、解決策はあるのでしょうか?  フロー制御で回避出きる問題ではありませんよね? 3)このFIFOバッファあたりの調査が可能なツールはありますでしょうか?出きれば、本当にFIFOバッファが一杯になる現象がデータとして取得出きればうれしいのですが。 現在、MSCommの設定としては以下の通りです。 Settings=115200,N,8,1 InBufferSize=3000 Handshaking=2 以上、1)~3)すべてでなくても構いません、よろしくお願いします。

  • Vargas
  • お礼率85% (174/204)

質問者が選んだベストアンサー

  • ベストアンサー
  • kabasan
  • ベストアンサー率44% (264/588)
回答No.3

全てお察しの通りです。 おそらくWin2000マシンの方はパワーがあるので間に合っているが、Meマシンはパワー不足で間に合わず、フロー制御がかからないため、デバイス上のFIFOバッファを使い切り、そこでデータを喪失しているのでしょう。 バイナリーファイルのやりとりならソフトウェアフローは使用できませんね。相手側にもちゃんとハードウェアフローをしてもらうしかないでしょうし、それで解決するはずです。 それと、前回の回答でも書きましたが、ケーブルのせいかもしてないので、その辺はきちんと調査して切り分けてくださいね。

Vargas
質問者

お礼

本当にわかりやすく説明して頂き、ありがとうございました。

その他の回答 (2)

  • kabasan
  • ベストアンサー率44% (264/588)
回答No.2

受信バッファは3000バイトを指定していますから充分ですね。 MSCommのフロー制御はデバイスの受信バッファ(16バイト)の使用量によって自動的に制御線を操作してくれるはずですから、以下の2点が怪しいと思います。 ・ケーブルの結線でRTS、CTSが自分自身に戻されている。 ・相手側がフロー制御無しになっている。 MSCommのプロパティでHandshaking=0、RTSEnable=Falseとしてみて動作させ、相手がデータを送信してくるようなら、フロー制御ができていません。一度試してみてください。 あと、あんまり解決にならないんですが、コンパイルオプションで速度重視にすれば、エラーの確率をちょっぴり落とせるかも。

Vargas
質問者

補足

ご回答ありがとうございます。 おっしゃる通り、Handshaking=0、RTSEnable=Falseで試してみても相手からデータを送信してきました。 これはフロー制御が出来ていないという事ですね。バイナリ-送受信の為、ソフトウェアフロー制御を行いたくないので、 MSCommの設定としてはHandShaking=2にして、RTSEnable=Trueとする設定を行い、相手側もそれに あわせるという事でよろしいのでしょうか?また、この問題はハードウェアフロー制御を行う事により、 完全に解決されるのでしょうか?あと、このエラーというのは私の推察通り、やはりFIFOバッファー(メインメモリー上 の受信バッファーではなく)上のデータ喪失と捉えてよろしいのでしょうか? 以上、再度ご回答願えればうれしいです。

  • ginyou
  • ベストアンサー率32% (138/431)
回答No.1

 えっと、通信の受信バッファを何バイトにしていますか?  文章を読むと意味不明なところがあるんですが、受信バッファを1024バイト程度にしておけば、十分間に合うとおもうんですが、  逆に、受信バッファ1バイトとかするとまず間に合いませんよ。(通信速度にもよりますが)

Vargas
質問者

お礼

ありがとうございました。

関連するQ&A

  • VB RS-232C 通信プログラム

    何度もお世話になっております。(VB6.0 MSCommを使用した通信プログラムを作成中です。)私は新卒で食品会社に入社したのですが,プログラムの分かる上司が身近では誰1人といない状況で困っています。 今作成しているのは,重量計に荷物が乗った段階で作業者がデータ転送ボタン(重量計についている)を押すと,重量計のデータ(500kgというデータ)をシリアルでCOM1に取り込み,フォームにエクセルのセルを作成し(OLEを用いて)保存できるようにしたいと考えています。 (重量計から送られてくるデータのフォーマット) 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 S T , N T , + 0 0 1 2 . 3 4 k g CR LF ST ; ヘッダ1 NT ; ヘッダ2  CRLF ; ターミネータ                   の18バイトのデータです。 ここで質問なのですが (1) 以下のプログラムで重量はバイト配列に受信できていますでしょうか?(実際に重量計とPCを接続できれば良いのですが工場の稼動状況が関わっておりすぐにはできません。) (2) 18バイトのデータを受信するからと言って RThreshold = 18 として良いのでしょうか? 普通,データは1バイトずつ送られてくると思うので RThreshold = 1としてイベントを発生させる必要があるのかとも思うんですが。 'MSComm1,2(COM1,2)コントロールの初期設定 Private Sub Form_Load() MSComm1.CommPort = 1 '通信ポートを設定 MSComm1.Settings = "9600,n,8,1" '通信条件の設定 MSComm1.RThreshold = 18 '固定長のデータ End Sub Private Sub Port1_Click() 'Port1_Clickのクリックイベントプロシージャ If MSComm1.PortOpen = False Then 'シリアルポートのオープン MSComm1.PortOpen = True End If LPort1.Text = "" 'テキストボックスのクリア受信 End Sub Private Sub MSComm1_OnComm() '受信のOnCommイベント Dim Buffer1(0 To 17) As Byte '受信バッファの変数宣言(18バイト) Select Case MSComm1.CommEvent 'CommEventプロパティに対する処理 Case comEvReceive '受信データ有り    Buffer1 = MSComm1.Input '受信データをバッファに格納 'これより下は受信した18バイトから必要なデータ8バイト目から4バイト分切り出し,dという配列(4バイト)に格納できないかと考えました。 Dim i As Integer Dim d(0 To 3) As Byte d = MidB(Buffer1, 8, 4) LPort1.Text = d 'LPort1.Text = Buffer1 '受信データをテキストボックスに表示 End Sub

  • こんにちは、VBはじめたての初心者です。MSCommコマンドを利用して

    こんにちは、VBはじめたての初心者です。MSCommコマンドを利用してマイコンと 通信するプログラムを作成中なのですが、わからないことがあるので質問させていただきます。 public aub form_load() MSComm1.CommPort = 3 'ポート番号設定 MSComm1.Settings = "115200,N,8,1" '設定 MSComm1.PortOpen = True 'ポートオープン MSComm1.Handshaking = comNone 'フロー制御無し MSComm1.RTSEnable = False 'RTS制御無し MSComm1.RThreshold = 1 '1バイト受信毎にOnCommイベント発生 Dim txBuffer As String End sub 'テキストに表示した受信文字列を変数に格納、さらに必要な文字列だけ抽出する Private Sub botan_Click() txBuffer = Text2.Text x = InStr(1, txBuffer, "e" & vbCrLf, 1) txBuffer = Mid(txBuffer, x + 3, (Len(txBuffer) - (x + 2))) Text1.Text = txBuffer 'txBufferの内容確認用 End Sub Private Sub cmdr_Click() Text2.Text = "" MSComm1.Output = "r a0 s 00 j ff" & Chr(13) 'マイコンのデータを読み込むコマンド End Sub Private Sub MSComm1_OnComm() Select Case MSComm1.CommEvent Case comEvReceive Buffer = MSComm1.Input Text2.Text = Text2.Text & Buffer ・ ・ ・ End Select End Sub おおざっぱですがこのようなプログラムをつくりました。 目的は受信された文字列(テキストに表示)を変数に格納、さらに必要な文字列だけ抽出する ことなのですが、このプログラムだとデータを読み込むコマンドを送るボタンとそのデータを 変数に格納して必要な部分を抽出するボタンを二回押さなければならず面倒なので、botan_Click() の中の命令をそのままcmdr_Click()に入れたのですが、そうするとエラーが出てしまいます。 いろいろと試したのですがどうやらtxBufferの中に受信データが入ってくれないみたいです。 原因は何か。何かいい方法がないかアドバイスいただけたら幸いです。 やりたいことは、一回のボタンクリックで変数に受信データのほしいとこだけを格納させることです。 よろしくお願いします。

  • VB6.0のGPSシリアル通信について

    はじめまして。 VB6.0で、GPSシリアル通信を行っています。 シリアル設定は、MSComm1.Settings = "4800,n,8,1" にしています。 1秒毎にGPSデータは受信でき、すべて受信できています。 ただし、このGPSデータは、1秒間に下記のように6行分受信されます。 $GPRMC,131850,A,3603.5404,N,14008.5746, $GPGGA,131850,3603.5404,N,14008.5746, $GPGSA,A,3,27,09,02,05,21,29,10,15,,,, $GPGSV,3,1,11,27,27,193,33,09,13,199, $GPGSV,3,2,11,21,18,317,23,29,14,259,22, $GPGSV,3,3,11,07,01,033,00,18,00,295,00,28 そこで、上記6行分のデータのうち、初めの2行分だけを取り出したいと思っていますが、どうもうまくいきません。 どのようにすれば、初めの2行分だけを取り出すことができるでしょうか? 下記がソースです。 Private Sub MSComm1_OnComm() Dim Buffer1 As Variant Select Case MSComm1.CommEvent Case comEvReceive Buffer1 = MSComm2.Input If (InStr(Buffer1, "GPRMC")) Then Debug.Print Buffer1; Else (InStr(Buffer1, "GPGGA")) Then Debug.Print Buffer1; End If End Sub どなたか教えてください。 よろしくお願いします。

  • 232C通信の受信について

    232C通信にてVisualBasicの場合、MSCommのOnCommイベントというのがありますが、Cで使えるDLL等で同じようなもの(受信したときに発生する)ってあるのでしょうか?もしくはAPIとかでサンプルソースがあれば教えてください。 宜しくお願いします。

  • MSCommの受信について。

    VB6.0でMSCommを使っています。 受信データが例えば「00000 00000 000001111122222」 というようなレスポンスが帰ってくるのですが、これは元々 連続データ読み込み(RDSコマンド)で3個読み出したときの結果が 「00000 00000 00000」 次にある番地に書き込んだ値を読み出すコマンドでの結果が 「11111」と「22222」となっています。 これを連続して送信しているので、バッファにはこのように後ろに追加されています。 これをOncommイベントが発生した時に Buffer=MSComm1.Input としてBufferに保存していますが、その後、文字列操作関数を使って 3つを分割しようとしても上手くいきませんでした。 一応、実験としてボタンをクリックした時に str="00000 00000 000001111122222"とデータを入れ、 文字列操作関数を使ってこれを3つに分割することは可能でした。 なので、アルゴリズム的に間違っているというわけではないようですが、 それを実際にシリアル通信させ、Oncommイベント発生の時に させようとした場合、どうにも上手くうごきませんでした。 複数のコマンドを送信してその結果が返ってくるときに 各コマンドの結果を別々のテキストボックスなどに表示させたいです。 それにはバッファの値を必要な部分にわけ、抽出する必要があると思うのですが、 どのようにすれば実行可能でしょうか? 複数のレスポンスが一気に帰ってきた場合、 バッファからどのように必要データを取り出せばいいでしょうか?

  • シリアル通信(送信について)

    現在VB6.0を使用してシリアル通信(RS232C)をMSCOMMを使用して行いたいのですが、受信は出来たのですが、送信がうまくいかない状態です。 MSComm.Output = 送信文字列 & vbCr とすると結果の値を受信できる予定なのですがエラーですという値が返ってきます。 同じ操作をTera Term等で行うと結果が正しく返ってきます。 何故そうなるのかわからない状態で困っております。 何かアドバイス頂けないでしょうか。

  • MSCommのCommEventプロパティ

    質問させてください。 ↓コードで、通信エラーのイベントを取得したいのですが、COMポートは正常に機能しているのですが、comEvReceiveに正しい値(0)が 入らずにデータ受信ができません。 対策を教えていただけませんか? Dim Buffer As String Do '5桁受信するまで待機 DoEvents Loop Until MSComm1.InBufferCount >= 5 MSComm1.RThreshold = 1 Select Case MSComm1.CommEvent '通信ポートのチェック Case comEvReceive 'OK Buffer$ = MSComm1.Input Case Else 'NG ・ ・ End Select

  • RS232 通信(2)

    PC_b のプログラムです よろしくお願い申し上げます Private Sub cmdPort1_Click() '変数宣言省略 ' 使用するシリアルポートを設定します。 Port1.PortNumber = 3 ' 通信条件を設定します。 Port1.BaudRate = 9600 Port1.DataBits = 8 Port1.StopBits = 1 Port1.Parity = parNone ' 受信バッファのサイズを設定します。 Port1.InputBufferSize = 4096 ' 送信バッファのサイズを設定します。 Port1.OutputBufferSize = 4096 ' フロー制御の種類を設定します。 Port1.Handshaking = hsRtsCts ' シリアルポートをオープンします。 blnOpenRet = Port1.Open(3, 9600, 8, 1, hsRtsCts, parNone, _ 10000, 10000, iomBlocking) On Error Resume Next ' 使用するシリアルポート、通信条件を設定し、 ' シリアルポートをオープンします。 ' 文字列にCR+LFを付けてデータを送信します。 lngOutputRet = Port1.Output("abcdefg1234" & Chr(&HD) & Chr(&HA)) ' 受信処理を行います。 lngInputRet = Port1.Input(strInputString, 5) ' 送信バッファにデータが残っている場合、 ' すべてが送信されるまで待機します。 Do DoEvents Loop Until Port1.OutputBufferByteCount = 0 ' 送信バッファと受信バッファをクリアします。 Port1.ClearOutputBuffer Port1.ClearInputBuffer 'オープンしているシリアルポートをクローズします。 If Port1.Opened Then ' シリアルポートをクローズします。 Port1.Close End If End Sub 関連URL:http://www.okweb.ne.jp/kotaeru.php3?q=453883

  • COM16以上を設定を使用してシリアル通信したい

    現在、VB6.0を使用してシリアル通信の制御をしたいのですが、MSCOMMを使用するとCOMポートの番号が16以上のポートを設定しようとするとエラーになってしまいます。(私の設定がおかしいのかもしれませんが・・・。) 通信ポートを16以上のポートも使用できるようにするにはどの様にしたらいいのでしょうか?

  • MScommのOncommイベントが発生しない

    ACCESSでMScommオブジェクトを使用し、ある機器からデータの読み取りを行いたいのですが、肝心のOncommイベントが発生いたしません。 なにか、ライブラリの参照設定が必要なのですか? それとも、自分の設定間違い(不足)なのでしょうか? 前にVBでMScommを使用したことがありますが、なにも特別なことはしなかったような・・・(MSCOMM32.OCXを使用しています) 補足が必要であれば、追記いたします。