• ベストアンサー

MSCommを用いたRS-232-Cデータ転送

Visual Basic ver.6を用いてRS-232-Cデータ転送のプログラムを書いています。 転送には,MSComm controlを用いています。 コンピューター側から命令コードを測定器側に送信すると(例えば,MSComm1.OutPut = "F,3,300," & Chr(13)のように),測定器側からは次のようなテキストデータの転送が指定された回数だけ起こります: @C/R 数値データC/R 数値データC/R ・・・・ ・・・・ (指定回数繰り返す) そこで,質問ですが,このデータをMSComm1.Inputを介してきちんと取得する方法をお教えください。私がよく理解できいない部分は,「どのような形でbufferにデータが落ちているのか?」という部分と「繰り返し処理をどう記述するのか?」という部分です。多分後者は配列型変数を用いて「指定回数」だけ繰り返すことになると思いますが・・・・。 なお,データ転送の制御フォーマットはデータのみの転送で,STXもETXも使用していません。

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

  • ベストアンサー
  • osaosa42
  • ベストアンサー率60% (20/33)
回答No.6

こんばんは。 これで、試してみてください。 '<<送信側>> Private Sub Command1_Click() MSComm1.InputLen = 0 MSComm1.PortOpen = True MSComm1.Output = Text1.Text + Chr(13) MSComm1.PortOpen = False End Sub '<<受信側>> '起動時にポートを開いておきます。 'Timer1を貼り付けてIntervalを100程度に。 Private Sub Timer1_Timer() Dim strBuf As String strBuf = MSComm1.Input If Len(strBuf) <> 0 Then List1.AddItem strBuf End If End Sub もし、受信データ長が同じ長さなら、OnCommイベントで データ取得した方がいいのですが・・・

cholerae
質問者

お礼

大分,返事が遅れまして申し訳ありませんでした。 また,御助言ありがとうございました。 御助言の通り,Timer controlを使ってTimer Eventを発生させ,Timer1.Interval = 適当な値(実験では,50 msecくらいが適当)で機器からデータを取得するとうまく行きました。 参考までに記すと,氏の最後の助言をヒントにして,さらに次のようにすると完全にデータを取得できました。1データ(@ & VbCr)を取得したところでTimer1.Enabled = Falseにして,Handshakingをするようにコードすると,以後は一定長のデータが送信されてくるので,OnComm Eventを発生させてデータを取得することができました。 大分苦労しましたが,氏の助言,たいへん参考になりました。ありがとうございました。

その他の回答 (5)

  • ponnta
  • ベストアンサー率17% (31/179)
回答No.5

ANo.#3の訂正です。 もしかするとInputLen=0で一行(つまりCRまで読み込むのかもしれない)と書きましたが、 InputLenで指定したサイズまで一度に取り出しせました。 InBufferSizeが十分なサイズで、コマンドを送ってから Inputまで十分な時間を確保しているのであれば測定器側から データが来ていない可能性があります。 または、コマンド送信からInputまでの時間が短く、@C/R を受信したタイミングでInBufferからデータを読んでしまっているとか。

cholerae
質問者

お礼

再度の御助言ありがとうございます。 実を申しますと,現段階での「結論」はponntaさんご指摘のことを考えています。とはいうものの使っているノートがたびたびハングしているうちに「ハードディスクがクラッシュ」したようで,修理に1週間程度かかるはめに陥りました(心境は(;;)です)。 使っている機器の測定値を「瞬時」呼び出すコマンドがあって,コマンドボタンに連動させて呼び出しプログラムを書くと,最初のクリックでは最初の2文字しかバッファーに入りませんが,次のクリック以降はちゃんとデータがすべてバッファーに収まり,ちゃんと数値を呼び出すことができます(これ自身不思議な現象ですが)。 データは, @ C/R 5文字の数値データ C/R です。 従って,inputまで若干時間を開けるようなコードを記載してタイミングを計るか,ボーレイトを変えてテストするようなことを現在考えています。 「結果」は若干間が開きますが,後日報告します。 また,何か御助言等,思い付きましたらお知らせください。

  • i-touch
  • ベストアンサー率40% (170/415)
回答No.4

私が作った受信プログラムでですが、InputModeはバイナリにしていました。 Sub MSComm1_OnCommで、MSComm1.CommEvent が comEvReceive のときに MSComm1.Input していますが、バッファに入っているものを受け取ると、 CR で切れているわけではないので、Inputを繰り返して、前の文字列と 連結して、通信が終わったところで、文字列処理でCRのところまでを1行 として分割していました。なお、InBufferSizeは2048にしています。 もっといい別の方法があるのかもしれませんが。 N88からの移植は、何かと相違点があって大変ですね。 では

  • ponnta
  • ベストアンサー率17% (31/179)
回答No.3

INPUTを繰り返しても次のデータが読めませんか? 私見ではありますが。 bufferはリングバッファになっていてInBufferSizeでしていしたバイト数だけ、受信したデータが格納できる。 inputで読み込まなければInBufferSize以上受信したものは取りこぼしが起きる。(後からきたのが格納できずに捨てられる) inputでInBufferのデータが読み込まれる。読み込まれるのはInputLenで指定したバイト数(バイナリ時)、 このとき読み込んだバイト分、バッファの空きが増える。 (テキストは使ったことがなので良くわからないが、もしかするとInputLen=0で一行(つまりCRまで読み込むのかもしれない)) InBuffrtCountを使うとInBufferに格納されているデータのサイズを取得できるのでこれが2以上なら数値データも格納されているはずです。 たとえばInBuffrtCountが0になるまでInputを繰り返してみるとか・・・ CRはコントロールコードなので取得できると思います

cholerae
質問者

補足

御示唆,ありがとうございます。 バッファーの特徴がおぼろげながら理解できるようになりました。 これまでのところ,いろいろ条件を変えて(例えば,MSComm1.InputLen = いろいろな値)トライアンドエラーを繰り返していますが,うまくいきません。共通している事実は,MSComm1.InBufferCount = 4が最高値です。つまり,データの最初の1行しか読みこまないということです。 以前まで,この計器からのデータを取り込むために,N88-Basicでコードしたプログラムを使っていました。従って,一応 @ & chr(13) の後のデータもパソコンには送られているはずと思っています。 多分,「単純なミス」に起因してうまくいっていないような気がするので,現在は,初心に帰って,データが送信されているかどうか?からチェックしているところです。

  • yanmaa
  • ベストアンサー率45% (207/457)
回答No.2

うんざっくりしたプログラムは書いていただいた方がいいのですが 気になるのは.InputLen = 0で0にせずに処理しているのでは? あとバイナリモードでないとCrは取れないと思うのだけど .InputBufferLenの値を考慮してないとか 非常に簡単なプログラムになるとは思うのですが受信のみならば という事で補足願います。

cholerae
質問者

補足

御示唆ありがとうございます。 InputLen に関してはどんな値でも同じ結果でした。つまり,データの最初の1行,@ C/Rしか表示できませんでした。 また,InputBufferLenの値も今度の問題には関係ないようです。

  • prome
  • ベストアンサー率32% (64/196)
回答No.1

測定器の制御をされているのですね。私もそうです。 MSCommコントロールの使い方については、資料や例が少ないので、 大変です。がんばってください。 さて、測定器に命令を与えてからリターンが返ってくるまでの大体の時間は 把握されていますか?大体の時間がわかるなら、命令を発してからその時間 だけ待って(ポーズをかける)、MSComm1.Inputすると読めるでしょう。 この時測定器からのリターン文字列の長さが想定できるなら、 それだけ分のバッファをとっておけば1回で読めます。 リターン文字列の長さがわからないからといって、極端に長めに取ることは メモリを食いすぎるので、適当な長さ分を取って何回かに分けて読むことに なります。何回かに分けて読んだ文字列を&でつなぎ合わせるとよい。 MSCommコントロールは使いにくいといっても、フロー制御さえ間違わなけれ ば取りこぼしはありません。ただ測定器が命令に関係なくデータを垂れ流す 仕様であれば、取りこぼしもやむを得ませんが。

cholerae
質問者

補足

さっそくの御示唆,ありがとうございます。若干,補足します。 TXT1.text = MSComm1.Input の形で読み出せるのは最初の1行だけです。つまり,"@"だけです。質問に書いたのですが,「BUFFER」がどのようなものなのか?が理解できていません。最初のC/Rが来るとBUFFERはデータの取得を止めてしまうようです。従って,BUFFER SIZEを大きくとっても結果は同じです。 今度試してみようと思うことは,promeさんのヒントを基にして,1行読んで,表示し,bufferを空にし,1行読む・・・というような繰り返しが可能かどうか?です。 何かヒントがありましたらお教えください。

関連するQ&A

  • MSCommについて

    ↓例の桁数、データブロックが不定で連続して受信されます。 最後の1桁は(ETX)です。 (STX)XXXXXX...(ETX)(STX)XXXXX...(FS)XXXXX...(ETX)(STX)XXXXX.......(FS)XXXX...............(ETX) すべての桁数、データブロックが対象なので一度に受信します。 1. 質問はInputプロパティで1桁ずつデータをREC変数に読み込んで、ある条件で、Loop分を抜けたいのですが、 VB6の定義方法がわかりません。 1-1.最後の(ETX)の読み込み 1-2.先頭30桁  MSComm1.InBufferCount = 0 MSComm1.InputLen = 1 Dim REC As String Do DoEvents If MSComm1.InBufferCount Then REC = REC & MSComm1.Input If ..... '最後の(ETX)の読み込み '先頭30桁 Exit Do End If   End If Loop 2. スピート重視で処理するために、InBufferCountに値があったら、すべての受信データをRECにいれたいのですが 取得できていません。 アドバイスはございますか? MSComm1.InBufferSize = 2048 MSComm1.InBufferCount = 0 MSComm1.InputLen = 0 Dim REC As String Do DoEvents If MSComm1.InBufferCount >= 1 Then Exit Do End If Loop REC = MSComm1.Input

  • rs232cでの受信データ(mscomm)の受信方法VB6

    VB6で、シリアル通信プログラムを作っています。 機器からレスポンスが、02 00 44 03 61 62 63 03 72 0Dと9バイトくるのですが、 8バイト受信した後に、また、最後の0Dを1バイト目として受信しているので困っています。 on commイベントで以下のようにして受信データをテキストボックスに表示しているのですが、 Select Case MSComm1.CommEvent   Case comEvReceive       Dim Buffer() As Byte       Buffer() = MSComm1.Input       For t = 0 To 6 + Buffer(3)  ,BUffer(3)はデータ長です。       Text1.Text = Text1.Text & Hex$(Buffer(t)) & Chr(&H3A)       Next t 8バイト表示した後、1バイト受信が起こるので、Buffer(3)が範囲外となりエラーが起こります。 inputLenは0にしています。 この問題は解決するにはどうしたらよいでしょうか? 0Dは終了コードです。0Dを受信するまで、きちんと1バイトづづ格納していくなどというようにできたらよいのですが、、、 他にも簡単な方法があったらよいのですが、、、 よろしくお願いいたします。

  • MSComm; 必要なファイル、設定

    VB6で、ActiveXファイルを作成しています。 デバッカーでは、問題なく動作します。 CABファイルを作成して、ファイルをダウンロードさせて動作させると データ送信は、できるのですが受信データが取得できません。 Do - Loop処理を繰り返しているようです。 必要なファイル、プロパティ設定などございますか? ご意見をお願いします。 CABの中身; TEST.OCX ASYCFILT.DLL COMCAT.DLL MSMASK32.OCX MSMSKjp.DLL MSPRPJP.DLL msstdfmt.dll MSSTKPRP.DLL MSVBVM60.DLL OLEAUT32.DLL OLEPRO32.DLL VB6JP.DLL MSComm1.CommPort = 1 MSComm1.Settings = "9600,N,8,1" MSComm1.PortOpen = True MSComm1.InBufferCount = 0 MSComm1.InputLen = 1 '-----Outputプロパティによるデータ受信 MSComm1.Output = (STX) & "CMD" & (CR) '-----Inputプロパティによるデータ受信 Dim Buffer$ Do DoEvents If MSComm1.InBufferCount Then Buffer$ = Buffer$ & MSComm1.Input Select Case Buffer$ Case Chr(13) Exit Do Case Else End Select End If Loop

  • 高速シリアル通信での大容量のデータ転送について(mscomm)

    現在高速シリアル通信のプログラムを作成しています。なかなか検索で いろいろと探しているのですがデータ容量が増えるとどうしてもサンプル プログラムで同じ結果になってしまいます。 どういう現象かといいますと10000バイトぐらいのデータを転送するとどう してもデータ上のかけ落ちが発生します。 ボーレート:38400 or 19200bps データビット:8Bit パリティ:なし ストップビット:1Bit フロー制御:XonXoffRTSCTSあり データはバイナリィ転送です。 ==>送信側のプログラムでは以下通りです。   'バイナリデータファイルを読み込み For i& = LBound(bytBuf) To UBound(bytBuf) bytedata(LineCnt) = bytBuf(i&) If (LineCnt < 255) Then '255バイトずつ分割して送信 bytedata(LineCnt) = bytBuf(i&) Else 'タイマー処理(wait制御) MSComm1.Output = bytedata LineCnt = 0 bytedata(LineCnt) = bytBuf(i&) End If LineCnt = LineCnt + 1 Next i& 'WAIT掛けたり分割してデータを転送したり一括でデータを転送したり 行っています。 ==>受信側では以下の通りとなっております。 Select Case MSComm1.CommEvent    Case comEvReceive '受信データの取得 Buffer = MSComm1.Input 'あとはバイトデータを結合させて                    'おります。 データの送信や受信について教えていただきたいのですが特に受信側で 私が思うのでは送信データが早すぎて受信側が追いついていない状態 と思うのですが・・・ なにかいい方法や参考になるホームページ等がありましたら伝授お願いします。

  • VBへの変換の仕方 RS232C送信データとチェックサム

    以下のプログラムをVBに変換する仕方を教えてください。 サンプルプログラム 1110 CHKSUM=0 1120 FOR i=1 to LEN(A$)      'A$は送信データ 1130 CHKSUM=CHKSUM+ASC(MID$(A$,i,1) 1140 NEXT i 1150 C$=CHR$((CHKSUM+13) MOD 256) 1160 PRINT #1,A$;CHR$(13);C$; 私のVBプログラムは1110行から1150行まではそのままで CHKSUM=0 FOR i=1 TO LEN(A$) CHKSUM=CHKSUM+ASC(MID$(A$,i,1) NEXT i C$=CHR$((CHKSUM+13) MOD 256) としました。 送信部分を MSComm1.Output =A$ & CHR$(&H13) & C$ としてみましたが 1160行にあるセミコロン ";" はCHR$(&h3B) として送る必要があるのでしょうか? MSComm1.Output =A$ & CHR$(&h3B) & CHR$(&h13) ・・・・・・ また、データとしてA$="I 02"のチェックサムは "リ" となりますが正しいのでしょうか? 以上ご教示ください。

  • VB2005によるRS232C制御

    VB2005でZX-800L(TAKASAGO)を動かしたいのですがポートオープンできません。(オープンできるとREMOTOが点灯するはずなんですが…) 現在MSCommまたは確認の意味でNSPcomを用いています。(シリアルポートもあるんですができれば前者でやりたい) 機器の設定は何度も確認して間違いはないと思われます。(windowsXP使用)プログラムは以下です。 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '<RS232C constant> STX = "02" EOT = "04" ENQ = "05" '伝送キャラクタ設定 ACK = "06" NAK = "15" ETX = "03" RTN = "0A" Comport = 1 OP = "9600,n,8,1" 'baud rate,stop bit,data bit,parity ADD = "01" 'RS232Cアドレス BC = "\" & EOT & ADD 'EOT+ADD Call ATH(BC) 'アスキー変換サブルーチンです。 EOTADD = BCH または (MSComm.CommPort = 1 'RS-232Cポート番号 MSComm.PortOpen = True MSComm.Settings = "9600,n,8,1" MSComm.RThreshold = 1 MSComm.SThreshold = 1 MSComm.RTSEnable = False MSComm.InputMode = MSCommLib.InputModeConstants.comInputModeBinary) End Sub この後、クリックイベント ret = Me.NspCom.ComOpen(Comport, OP) If ret = -1 Then MsgBox("miss") End If または (MSComm.PortOpen = true) でオープンさせたいのですが… 機器のHPにもサンプルプログラムもなく困っています。助言&ご指摘お願いします。

  • VBでRS232Cの制御について。

    通信のデータ長やパリティ、ポーレート等の設定を”SETTINGS”でおこない、ポートをオープンして外部機器にデータを送る際、ここでは、データをバイナリデータで送らなければなりません。 STX,アドレス,チェックサム,ETXの順にそれぞれアスキーコードで16進数に変換して送ってますが、うまく通信できません。 教えて頂けませんか。 素人でごめんなさい。 この部分のサンプルプログラムがあれば最高なんですが・・・。

  • データ送信

    MSCommのOutPutプロパティを使用して送信します。 Dim Buffer As String  Buffer = "Dummy" MSComm1.Output = Buffer RS-232C接続をしたデバイスにデータを送信します。 このとき、受信するデバイスがいないとMSComm1.Outputステートメントの処理に約4-5秒かかります。 これは仕様ですか? MSComm1.Iutputプロパティを含めて、タイムアウトに関して参考になるドキュメントやサイトがございましたら教えていただけませんか?

  • Mscomm を使用してバイナリでデータを受信したい

    Mscommを使用して、垂れ流しデーターをバイナリで受信(受信データ長さは変化する)するとき、このデーターをどうやって、配列に格納していけば良いのでしょうか? (垂れ流しデータ ⇒ < STX >nnn-nnn・・・・< ETX >< CHK >) また、配列に格納したデーターを文字に置き換えるにはどうすれば良いでしょうか? まず考え方として以下の流れでよいでしょうか? バイナリデータをバリアント型の変数に入れる。(受信する)      ↓ このデータを1バイトごとにバイト型変数の配列に入れていく。      ↓ 格納した配列の中の制御文字を取り除く。( ST、EX )      ↓ 配列に入っているデータを文字に変換する。      ↓ 変換した文字をつなぐ。 受信するデーターが制御文字を含んでいる為、テキストで受信するとおかしな動作をすることがあるので(150バイト程度のデーターを、バッファから変数に移すときに、0.5~2.5秒もかかってしまうし、文字化けも時々起こす。)バイナリで受信してその後文字に変換したいのですが・・・。 宜しくお願い致します。

  • 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