• ベストアンサー

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

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

  • ベストアンサー
回答No.5

>★キャラクタ長 7bit >★パリティ 偶数 のデータを >★キャラクタ長 8bit >★パリティ 無し で受け取った場合、 LFが文字化けします。 そのため、“Case vbLf”は通りません。 ※s = MSComm1.Input の後に ※MsgBox "s=" & s ※または ※MsgBox "s(hex)=" & Hex$(s) ※を入れて確認すればすぐに判ります。

hiroki1227
質問者

お礼

非常に助かります。有難うございます。資料の確認不足でした。 1点疑問な点がですが, 今現在,Win-NTで重量計とデータのやり取りをしているのですが,疑問なの点として,PC上のCOM1の設定では,キャラクタ長 8bit,パリティ無しで設定されているのにデータは受信できています。プログラム上ではおそらく,キャラクタ長 7bit,パリティ 偶数 で設定されています。 この状態で正確にデータが受信できている点が不思議です。 (Win-NTで使用しているプログラムをWin-XPでセットアップしようとした所できなかったため,プログラムを新たに作成している訳です。新しいPCに替えたいため)

その他の回答 (4)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.4

その設定でよさそうですが … デフォルトだと InputLen=0 ですと読み込んだバッファ全て取り込んでしまうので先に投稿したような現象に見舞われているのかと思った次第です 先の投稿は select case s ブロックを置き換えるように考えたものです 2文字以上取得してしまった場合 s1に左端の1文字を取得 ... 1) sを2文字目以降に更新 s1でデータの検証 s1が""以外なら 1)に戻ってループ

hiroki1227
質問者

お礼

回答有難うございます。 先ほど通信プロトコルを調べていた所,誤っている点がありました。 Private Sub Form_Load() MSComm1.CommPort = 1 '通信ポートを設定 MSComm1.Settings = "9600,n,8,1" '通信条件の設定 MSComm1.RThreshold = 1 '固定長のデータ MSComm1.InputLen = 1 End Sub とプログラムではしていたのですが, RS-232C プロトコル ボーレート 9600bps ★キャラクタ長 7bit ★パリティ 偶数 ターミネータ CR+LF ストップビット 1bit と重量計のほうでは設定されているようです。 (1) この間違いがデータを取得できない原因になっているのでしょうか? (2)またテキストボックスに何も表示されないということは,ターミネータでブロックされていない点が問題なのですか?

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

(1)の場合受信したのが1文字を超えた場合破綻します Select case s としているので sが2文字以上になったしまった場合 case vbLFブロックでの処理が出来ません Dim s1 as String s1 = Left$(s,1) s = mid( s,2 ) while s1<>""   select case s1     'データの検証   end select   s1 = left$( s,1)   s = mid(s,2) wend といった具合に 確実に1文字ごとに判定するようにしましょう

hiroki1227
質問者

お礼

非常に感謝しております。以下の質問がありまして,申し訳ないのですが御願いします。明日にはデータが受け取れる状態にしたいと思っていますので御願いします。 質問(1) 示して頂いたものを,前回の示したサンプル(1)に加えるとどのようになるのですか?本を参考にして調べたのですが,わからなくて困っています。  Dim s1 as String s1 = Left$(s,1) s = mid( s,2 ) while s1<>""   select case s1     'データの検証   end select   s1 = left$( s,1)   s = mid(s,2) wend (2)1文字以上受信した場合,ターミネータVbLfでブロックできない点は理解できたのですが,MSComm1.InputLen = 1 , MSComm.RThreshold = 1 は1文字を受信できるように設定しているのではないのですか?ずっとそのように思っていたのですが。自分の理解が違っているのですか?

回答No.2

>MSCommを用いなくても重量のデータならハイパーターミナルを使用すれば簡単にデータは受信できるということなのですか?? 違います。ハイパーターミナルに重量計の代わりをさせるという意味です。 今回のように仕事に使うプログラムの場合、テストを十分行う必要があります。 正常なデータが送られた場合は勿論、ノイズで過不足のあるデータが受信された場合もテストした方が良いです。 そこで、ハイパーターミナル(または他の通信ソフト)を使っていろいろなデータを送って、プログラムが正常に動作するかをテストします。

hiroki1227
質問者

お礼

ご指摘ありがとうございます。 業務上に使うという意味では,ミスは許されませんのでハイパーターミナルで十分テストしたいと思います。

hiroki1227
質問者

補足

何度も申し訳ありません。前回示して頂いたサンプル(1)に変更し,重量計と実際に接続してデータを送っていたところ,テキストボックスに何も表示されませんでした。エラーも何も出なかった状況です。ただし,サンプル(2)を用いるとデータは送られるのですが,送られている上位ビットがおかしい為,正しくは送られていないのですが。(ASCII表で送ったデータと送られたデータを見比べていると,上位ビットがずれているため通信条件の間違いだと思っています。) 質問なのですが (1) サンプル(1)でもデータは送られてもいいと思うのですが?(テキストボックスになにも表示されない点が気になります)(通信条件間違っていたとしても何かしらのデータは送られていいと思うのですが?)  もし,データが表示されない原因がお分かりになりましたら教えて頂けますか? (参考になるかと思いまして,サンプル(1),(2)を示させていただきます) (サンプル(1)) Private Sub MSComm1_OnComm() '受信のOnCommイベント   Dim s As String   If MSComm1.CommEvent = comEvReceive Then  '指定された数の文字を受信した。     Do While MSComm1.InBufferCount > 0 'MSComm1にデータが有る間       s = MSComm1.Input       Select Case s         Case vbCr         Case vbLf           '受信したデータの8文字目から4文字を切り出す           Weight = Mid$(Buffer, 8, 4)           Buffer = ""   '次のデータに備えてBufferを初期化           LPort1.Text = Weight  '重量を表示         Case Else           Buffer = Buffer & s       End Select     Loop   End If End Sub ((2)) Private Sub MSComm1_OnComm() '受信のOnCommイベント Dim Buffer As Variant '受信バッファの変数宣言 Select Case MSComm1.CommEvent 'CommEventプロパティに対する処理 Case comEvReceive '受信データ有り Buffer = MSComm1.Input '受信データをバッファに格納 LPort1.Text = LPort1.Text & Buffer '受信データを順次表示する End Select End Sub

回答No.1

(1) MSCommからデータを受け取るバイト配列は、動的配列にしないといけません。 つまり Dim Buffer1() As Byte ReDim Buffer1(0 To 17) As Byte とします。 しかしながら、重量計からのデータがテキストのみなので、わざわざバイト配列を使わず文字列で十分です。 ※実際の重量計が無くても、ハイパーターミナルで十分代用できます。 ※ファイル→プロパティ→設定→ASCII設定→ASCIIの送信で、「行末に改行文字を付ける」「ローカルエコーする」にチェックを付ける。 ※転送→テキストファイルの送信で、予め用意したテストファイルを送信できます。 (2) もしノイズ等で1文字欠損(または追加)されたら、以後ずっとずれたままになります。 なので、1文字ずつ受信してチェックするほうが良いです。 私のサンプルソースは下記のようになります。 LFを受信した時に重量データを取得します。 受信したデータに過不足が無いかはチェックしてません。 全角スペースでインデント使用。 'モジュール変数 Private Buffer As String  '受信した文字列 Private Weight As String  '重量データ 'MSComm1,2(COM1,2)コントロールの初期設定 Private Sub Form_Load()   MSComm1.CommPort = 1  '通信ポートを設定   MSComm1.Settings = "9600,n,8,1" '通信条件の設定   MSComm1.InputLen = 1  '一度に1文字ずつ   MSComm1.RThreshold = 1 '固定長のデータ 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 s As String   If MSComm1.CommEvent = comEvReceive Then  '指定された数の文字を受信した。     Do While MSComm1.InBufferCount > 0 'MSComm1にデータが有る間       s = MSComm1.Input       Select Case s         Case vbCr         Case vbLf           '受信したデータの8文字目から4文字を切り出す           Weight = Mid$(Buffer, 8, 4)           Buffer = ""   '次のデータに備えてBufferを初期化           LPort1.Text = Weight  '重量を表示         Case Else           Buffer = Buffer & s       End Select     Loop   End If End Sub

hiroki1227
質問者

お礼

有難うございます,助かりました。 1点だけ質問させてください。 ※実際の重量計が無くても、ハイパーターミナルで十分代用できます。 ※ファイル→プロパティ→設定→ASCII設定→ASCIIの送信で、「行末に改行文字を付ける」「ローカルエコーする」にチェックを付ける。 ※転送→テキストファイルの送信で、予め用意したテストファイルを送信できます。 ※で示した頂いた件について詳しく教えて頂けませんか? 今回はMSCommを使用しているためハイパーターミナルの必要性はないと思うのですが?? 今回ハイパーターミナルについて示して頂けたのは,MSCommを用いなくても重量のデータならハイパーターミナルを使用すれば簡単にデータは受信できるということなのですか?? 何度も質問して申し訳ありません。

hiroki1227
質問者

補足

何度も申し訳ありません。前回示して頂いたサンプル(1)に変更し,重量計と実際に接続してデータを送っていたところ,テキストボックスに何も表示されませんでした。エラーも何も出なかった状況です。ただし,サンプル(2)を用いるとデータは送られるのですが,送られている上位ビットがおかしい為,正しくは送られていないのですが。(ASCII表で送ったデータと送られたデータを見比べていると,上位ビットがずれているため通信条件の間違いだと思っています。) 質問なのですが (1) サンプル(1)でもデータは送られてもいいと思うのですが?(テキストボックスになにも表示されない点が気になります)(通信条件間違っていたとしても何かしらのデータは送られていいと思うのですが?)  もし,データが表示されない原因がお分かりになりましたら教えて頂けますか? (参考になるかと思いまして,サンプル(1),(2)を示させていただきます) (サンプル(1)) Private Sub MSComm1_OnComm() '受信のOnCommイベント   Dim s As String   If MSComm1.CommEvent = comEvReceive Then  '指定された数の文字を受信した。     Do While MSComm1.InBufferCount > 0 'MSComm1にデータが有る間       s = MSComm1.Input       Select Case s         Case vbCr         Case vbLf           '受信したデータの8文字目から4文字を切り出す           Weight = Mid$(Buffer, 8, 4)           Buffer = ""   '次のデータに備えてBufferを初期化           LPort1.Text = Weight  '重量を表示         Case Else           Buffer = Buffer & s       End Select     Loop   End If End Sub ((2)) Private Sub MSComm1_OnComm() '受信のOnCommイベント Dim Buffer As Variant '受信バッファの変数宣言 Select Case MSComm1.CommEvent 'CommEventプロパティに対する処理 Case comEvReceive '受信データ有り Buffer = MSComm1.Input '受信データをバッファに格納 LPort1.Text = LPort1.Text & Buffer '受信データを順次表示する End Select End Sub

関連するQ&A