• 締切済み

シリアル通信でコマンドを送信し、戻ってきたら実行する

VB初心者です。ぜひ、お分かりになる方がいらっしゃいましたら教えて下さい。 質問1:輝度計をシリアルポートに接続し、測定実行のコマンドを送信し、測定後にOKが戻ってきたら測定結果を受信するコマンドを送って結果を受信するというプログラムをVBで作成しています。MScommを使用し、測定実行コマンドを送信後、OKが戻ってくるところまでは出来たのですが引き続き、測定結果を受信するコマンドを送っても反応がありません。やけになって2行続けて書いたらなぜか、2行目が先に実行されてしまいました! 質問2:シリアルポートが開いたらForm2を開き、フォームの色をRGB関数で0に設定、測定コマンドを送信後に結果を受信したらフォームの色を1にするということを 繰り返し、255色まで行いたいのですがFor Nextで設定しても色が変わってくれず、なぜか255の白になってしまいます。色々、調べたのですがよく分からなくて。 とてもこまっています。宜しくお願いします。 Max = 255 For i = 0 To Max r = i: g = i: b = i FrmColor.BackColor = RGB(r, g, b) Next End Sub

みんなの回答

  • Pesuko
  • ベストアンサー率30% (2017/6702)
回答No.8

あんまり詳しくないですが、 全体の流れがおかしいような感じがします。 ”GM”送出後”OK”を受信するまで次の処理をしてはいけないです。 大まかな流れとして。 1)GM送出 2)”OK”ポーリング&タイムアウト処理 3)”OK”正常受信時 4)”OR”送出 5)データ受信ポーリング&タイムアウト 6) 2)のタイムアウト処理 7) 6)のタイムアウト処理 Hayashi_Trekさんがおっしゃるように、よく勘違いするのが対象機の処理に非常に時間がかかる事を忘れて一気に処理をしてしまうと結果がバラバラに受信してしまう場合があります。 このような事象も前述のプロトコルアナライザーを使って通信内容を見るとコマンドの順番がおかしいことがすぐに解るんです。

回答No.7

このソースでは正常動作は難しいと思います。 なぜなら >' GMコマンド送信後OKが戻ってきたら の処理部分が無いため、GMコマンドとORコマンドが立て続けに送られます。 輝度計が測定開始するには時間が掛かると思います。 それに対して結果を返すのはすぐ出来ます。 だから測定開始がOKになる前に、前回の測定結果が返されているのでしょう。 私が良く使う方法は、状態モードで処理分けする方法です。 大雑把な例を書いておきます。受信データの取り込み部分はまだまだ改善が必要です。 Private m_Mode as Integer ' 状態モード ' m_Mode = 0 : 初期状態 ' = 1 : GM送信 ' = 2 : GM応答待ち ' = 3 : OR送信 ' = 4 : OR応答待ち ' = 5 : 終了 ' 送信のClickイベント Private Sub cmdSend_Click() ' 処理のLOOP  m_Mode = 0  Do Until m_Mode=5 ' 終了状態になるまでループする   Switch Case m_Mode   Case 0    ' 通信ポート開く     mscPort.PortOpen = True     m_Mode = 1   Case 1    ' GMコマンド送信     mscPort.Output = "GM" & Chr(&HA)     m_Mode = 2   Case 2   Case 3    ' ORコマンド送信     mscPort.Output = "OR" & Chr(&HA)     m_Mode = 4   Case 4   Case 5   End Select   DoEvents  Loop  ' 通信ポート閉じる   mscPort.PortOpen = False   m_Mode = 0 End Sub ' MSCommコントロールのOnCommイベントプロシージャ Private Static Sub mscPort_OnComm() ' 変数宣言 Dim varBuffer As Variant '受信バッファ  ' CommEventプロパティに対する各処理  Select Case mscPort.CommEvent  ' イベントメッセージ  Case comEvCD ' CD ラインの状態が変化しました。  Case comEvCTS ' CTS ラインの状態が変化しました。  Case comEvDSR ' DSR ラインの状態が変化しました。  Case comEvRing ' リング インジケータの状態が変化しました。  Case comEvReceive ' RThreshold プロパティで指定された数のバイトを受信しました。   ' 受信データの取得   Select Case m_Mode   Case 0   Case 1   Case 2    ' OK待ち    varBuffer = mscPort.Input    If varBuffer="OK" Then     m_Mode = 3    End If   Case 3   Case 4    ' 測定値待ち    varBuffer = mscPort.Input    m_Mode = 5   Case 5   End Select  End Select End Sub

wanta_k
質問者

お礼

別の仕事が入ってしまい、しばらくVBから離れていたため、試せずお礼が遅くなってしまって申し訳ありませんでした。 細かいリソースまで作って頂いてとても感謝しています。 その後、作って頂いたリソースを元にプログラムを変更して実行した結果、正常に 動くことを確認出来ました。順番に実行するためにはどう書いて良いのかが分からず、続けて書いてしまっていたためとご指摘のとおり、コマンドの戻り時間を考慮していなかったために逆に実行されているように思い込んでしまいました。 プログラムとしては他にもまだまだ改善が必要ですがとても勉強になりました。 また、何かありましたら宜しくお願い致します。 本当に有り難うございました。

  • k-family
  • ベストアンサー率34% (180/523)
回答No.6

説明が矛盾していますよ。 > ' GMコマンド送信後OKが戻ってきたら ですからGMコマンドは実行されているのではないですか。 やはり状況が良く把握できません。 できる限りシンプルなプログラムを作って見せて頂けますか。 (でもやはり解決できる自信がないですけど・・・。#2,#3,#4の方いかがですか?)

  • k-family
  • ベストアンサー率34% (180/523)
回答No.5

良く把握できないのでお役に立てそうもないのですが、 >' GMコマンド送信後OKが戻ってきたら というのはこの書かれたリストでは省略されているのですよね? 「逆に実行される」とはどういうことなんでしょうか。GMコマンドは測定開始なんですよね。OKが帰ってきたと言うことは無事実行されたのではないんですか? ------ #2の方がかかれた、DoEventsは制御をOSに戻すための物です。時々OSに戻してやらないとマウスやKBやシリアルの入力を受け付けませんから。

wanta_k
質問者

補足

>' GMコマンド送信後OKが戻ってきたら >というのはこの書かれたリストでは省略されているのですよね? はい、どのように記載してよいのか分からなかったので。 試しにifで書いてみたのですが・・・だめでした。 >「逆に実行される」とはどういうことなんでしょうか。GMコマンドは測定開始な>んですよね。OKが帰ってきたと言うことは無事実行されたのではないんです ? ハイパーターミナルのように戻り値をテキストに表示するような設定を行っているのですがORコマンド戻り値が先に表示されてしまいます。 OR,0.8 GM,OK   というような感じです。 宜しくお願い致します。

  • Pesuko
  • ベストアンサー率30% (2017/6702)
回答No.4

お問い合わせの回答ではないですが、シリアル通信は電文が正確に出ているかどうかがわかりにくいので、ぜひプロトコルアナライザーを使用しましょう。 ビッツ社のみえちゃん・旧積水電子(現ラインアイ社)のラインアイ等。 弊社では「嘘発見器」と呼んで必需品です。 殆どの不具合がアナライザーを通すと解ります。 良くあるのがデリミタ(.や:)やエンド(CRやLF)の付加忘れです、プログラム上絶対出ているはずが、数十回に一回だけ付加されないとか。 買うことが出来なくても知り合いが持っていれば1日だけでも借りればすぐに解決しますよ。 おおむね定価20万円前後です。 ビッツ http://www.bits.co.jp/hm/hm2g.htm ラインアイのうちLE1100 http://www.lineeye.co.jp/le1100.htm

  • fantasis
  • ベストアンサー率26% (14/52)
回答No.3

一応2のほうの解凍を記しときます。 この際はタイマーコントロールによるタイマーイベントで行ったほうが良いと思います。 まず、タイマーコントロールをフォールに張りつけダブルクリックします。そのつぎには次の文を試してみてください。 (この際、Timer1.Interval=1とします) Option Explicit Dim r as Byte, g as Byte, b as Byte Private Sub Timer1_Timer() If r >254 Then Timer1.Interval = 0 Else r = r + 1 g = g + 1 b = b + 1 End If FrmColor.BackColor = RGB(r,g,b) End Sub で出来ると思います。ちなみにお勧めは増分値を5にしたら結構良い具合になります。

wanta_k
質問者

お礼

お礼が遅くなってしまい、申し訳ありませんでした。 有難うございます。教えて頂いたとおりに記載してみたところ、 色の変更は順番とおりに出来ているようです! ただ・・・早すぎるみたいでビデオの早送りのようになって しまいます。Timer1.Intervalの数字をいくつか変えてみたのですが (1000とか5000等etc・・・)だめでした。(うっ) 例えば5秒たったら次のフォームの色に変えるというように(255色まで) するのは難しいのでしょうか??? 宜しくお願い致します。

  • ykkw_2001
  • ベストアンサー率26% (267/1014)
回答No.2

現在のプログラムとか、計測器の通信仕様とか、もうちょい、具体的であればいいんですが・・・ 1: >なぜか、2行目が先に実行されてしまいました 1行目の分は、実行されないわけでしょうか? もしそうなら、「輝度計」側の受信ソフトが遅くて、1行目は、「測定実行->OK」の処理中になってしまい、無視された。 あるいは、電文の区切りが違っていた。 あるいは、MSCommの設定ミス。 2: 多分、色変更が早すぎるからです。 For ループ内に DoEvents を書き加えるか、 タイマーを使ってゆっくリ色を変えるようにして、試してください。

wanta_k
質問者

お礼

ご連絡が遅くなってしまい、申し訳ありません。 ご回答有難うございました。 2:についてご指摘頂いたことについて試していました。やはり、早く実行されて いるために白しか表示されていないように見えているようです。 その後、タイマーなどを使って5秒で設定し、行ってみたのですが・・・ なぜか、状況は変わりません。具体的にはfrmColorにタイマを1つ設定して 上記質問のfor文を記載して見たのですが。DoEventsについては色々インターネットでも調べてみたのですが記載の仕方が良く、分かず試せませんでした。 もし、よろしければどのように記載したらよいのかを教えて頂けると嬉しいです。 尚、1:についてもご指摘のとおりに思いますが測定器が会社ですのでまた、 調べてみます。

  • k-family
  • ベストアンサー率34% (180/523)
回答No.1

お困りのようですが、情報が少なくて答えられる人は少ないと思います(特に1番)。もう少し具体的に書いてみてはいかがでしょうか。だからといって私が答えられるとは限りません。でも他の方から回答を得られやすくなります。 2番の方ですが、これは一部分を取り出したんですよね。このままだとしたら、一瞬で0~255まで行ってしまうので白になるような気がします。 それから1番と2番は直接関係なさそうですから別々に聞かれた方が回答を得られやすいと思います。

wanta_k
質問者

補足

状況の説明が悪くて申し訳ありません。。。 手順としては送信コマンドをクリックしたらCOMポートをを開く→測定開始コマンドを送信する(GM)→輝度計が測定を開始→OKが戻ってきたら輝度計の測定結果を戻すコマンドを送信(OR)→データを受信という形になります。以下に、作成中のプログラムを記載します。 (初心者ですのでプログラムの乱雑さはお許し下さい! ' 送信のClickイベント Private Sub cmdSend_Click() ' 通信ポートか開いているか確認 If mscPort.PortOpen = True Then   ' Colorフォームを開く   FrmColor.Show   ' 受信データの一時取得用変数の初期化   strData = ""   ' MDT測定を要求するコマンドを送信   strSendData = "GM"   mscPort.Output = strSendData & Chr(&HA)   TxtSendData.Text = strSendData   ' GMコマンド送信後OKが戻ってきたら   If strSendData = "GM" Then ←この行をコメントするとGMとORが    strSendData = ""     逆に実行されてしまいます。     ' 測定結果を要求するコマンドを送信     strSendData = "OR"    mscPort.Output = strSendData & Chr(&HA)    TxtSendData.Text = strSendData     FrmColor.BackColor = RGB(r, g, b)   End If End If End Sub ' MSCommコントロールのOnCommイベントプロシージャ Private Static Sub mscPort_OnComm() ' 変数宣言 Dim varBuffer As Variant '受信バッファ ' CommEventプロパティに対する各処理 Select Case mscPort.CommEvent ' イベントメッセージ Case comEvCD ' CD ラインの状態が変化しました。 Case comEvCTS ' CTS ラインの状態が変化しました。 Case comEvDSR ' DSR ラインの状態が変化しました。 Case comEvRing ' リング インジケータの状態が変化しました。 Case comEvReceive ' RThreshold プロパティで指定された数のバイトを受信しました。 ' 受信データの取得 varBuffer = mscPort.Input TxtRecieveData.Text = TxtRecieveData.Text & varBuffer 送信コマンドはtxtSendDataに表示され、コマンドの送信結果はtxtrecivedataに表示されるように作成しています。ぜひ、宜しくお願いします。

関連するQ&A

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

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

  • VB2010で、シリアル通信の方法を教えてください。

    VB2010で、シリアル通信の方法を教えてください。 ツールボックスの「Serial Port」を使っています。 送信までは難なくできたのですが、受信が旨くいきません。 参考にしたサイトは、 http://msdn.microsoft.com/ja-jp/library/cc720852.aspx です。 これを実行すると、受信が出来ないだけでなく、フリーズしてしまいます。 どうやったら、受信できるのでしょうか?

  • VB2008でコマンド実行

    VB2008のフォームからボタンをクリックして、DOSコマンドを実行したいのですが うまくいきません。 http://dobon.net/vb/dotnet/process/standardoutput.html にあるサンプルをそのまま貼り付けて実行したら Console.WriteLine(results)の実行結果が空白になります。 Debugで見ると BasePriority = {"プロセスは終了しているため、要求された情報は利用できません。"} という表示があるのですが、このサイトのコメントでは、出来ると書いてあるので何が 悪いのか分かりません。 分かる方がいらっしゃったら教えてください。お願いします。

  • シリアル通信ができません

    VBの5.0を使っています RS232Cケーブルで計測器の制御・情報取得を目指していますが上手くいきません このサイト(http://spectrum123.at.infoseek.co.jp/vb/vb_5/vb_5.htm) を参考にしています 現状では実行すると制御機器が「Remote Mode」を表示するので何らかの信号が出ていることは間違いないのですが 計測器の説明書にしたがってコマンドを送信してもリアクションがありません どうか、よろしくお願いします

  • コマンドプロンプトのシリアル通信について

    最初に、プログラム等の知識が乏しいので、説明がわかりづらければすいません。 貴金属向けの計量器をPCから制御できる方法を探しております。 計量器にあるコマンドを送る事で、計量値を0にしたり、結果を返す事が出来るようです。 というのも、計量器メーカーの出している専用アプリケーションを利用すれば、そのあるコマンドを送り、計量器からの戻り値も受信できるのですが、他アプリへ連携したいので、その専用アプリを介さず制御したいのです。 あるコマンドというのは、 ・計量値を0にする(リセット)=”R”+改行コード ・計量結果を取り出す=”PRT”+改行コード 自分でも色々と検索し、コマンドプロンプトで、 type C:\test\R.txt > com5 のようにテキストファイルの中身を計量器(COM5)へ送る事で、計量値を0にする事は成功しました。 テキストファイルの中身は文字列”R”と改行コードです。 計量した結果を計量器から取り出す為には、 文字列”PRT”+改行コードを計量器に送り、計量器から戻り値として、 【1.12g】のように返ってきます。 この返ってきた情報をコマンドプロンプトでPCに取り出す事は可能でしょうか? また不可能であればPowershellで行う方法もありますでしょうか? もし方法をご存じの方がいらっしゃれば教えていただけないでしょうか。 宜しくお願いします。 ちなみに計量器に送信するコマンドについては、シリアル通信をモニターできるフリーソフトを利用し、テストしているのであっていると思います。 添付画像を参照ください。 ※50 52 54 0d 0a=”PRT”+改行コードを送信し結果(20 20 20 20 20 20 20 20 30 2e 30 32 20 67 0d 0a= 4.82 g+改行コード)が返ってきたときの画像です。

  • DOSにコマンドを送って実行

    DOSモードでしか実行できないソフトがあるんですが、 VBからそのソフトをDOSで実行し、コマンドを送って、結果を得られるようにしたいのですが。 それと、DOSで実行している過程は表示されないようにしたいです。 そのソフトの使用方法は起動してコマンドを入力するだけで結果が出てきます。 どなたかご存知の方がいらっしゃいましたら宜しくお願い致します。

  • シリアル通信について。

    PICからPCにデータ(電圧:最大値5)を受信させようとしています。 受信には C++を用いたプログラムを自作したいのですが、 どうしてもうまくいかなかったため投稿させていただきました。 症状としては、まずポートを開く事すら出来ていません。 RS232c {USBで変換) が接続されているポートはCOM1です。 ポートが開くか確かめるプログラムとしては、次のようなソースを使いました。 #include<windows.h> #include<iostream> using namespace std; int main(void){ HANDLE hCom; hCom = CreateFile( (LPCWSTR)"COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hCom == INVALID_HANDLE_VALUE) { cout<<"シリアルポートを開くことが出来ませんでした。\n"<<endl; return false; } CloseHandle( hCom ); return 0; } これを実行すると「シリアルポートを開くことが出来ませんでした。」としかなりません。 ( (LPCWSTR)"COM1"となっているのは、「'CreateFileW' : 1 番目の引数を 'const char [5]' から 'LPCWSTR' に変換できません。」  と出てしまったためです。) ハイパーターミナルを用いてCOM1からデータを受信できていることは確認しましたので、 通信が出来ていないわけではないようなのです。 ありふれた質問である事は重々承知の上ですが、 このソースでシリアルポートが開けない理由を教えていただければ幸いです。 環境:Visual C++ 2008 Express Edition Microsoft Windows XP Version 2002 Service Pack 3

  • VB2010からコマンドの実行方法

    環境  VisualBasic2010Express  WindowsXPSP3 前提  あるプログラムをインストールしていると使えるコマンドがあります。  コマンドプロンプト上から、バッチファイルを実行すると正常動作します。  仮に j.bat とします。  内容は   dxf -o -s c:\test\test0.dxf   dxf -o -s c:\test\test1.dxf   dxf -o -s c:\test\test2.dxf  こんな感じです。  dxfの本体は、とあるフォルダにあるdxf.exeと思われます。  (同名ファイルが複数あるので、特定できていません)  パスが通っているのか、カレントディレクトリ(?)に関係なく実行可能です。  このバッチファイルを実行すると処理は正常です。 現状  VBでボタンを押したらバッチファイルと同じ処理をするプログラムを作りたいのですが  実行する内容が毎回変化します。(dxfコマンドの引数が変わる)   よって同じバッチファイルは使えません。  Dim Buffer(2) As String  Dim Ret(2) As Integer   for i =0 to 2    Buffer(i) = "dxf -o -s c:\test\test" & i & ".dxf"    Ret(i) = Shell(Buffer(i), vbNormalFocus)   next i  こんなプログラムですが、処理がされてません。  コマンドプロンプトは一瞬3個開きます。  dxfをフルパスで記述しても同じです。 質問(1)    コマンドプロンプト上にメッセージが出ているようなのですが    一瞬で消えるので読めません。    コマンドプロンプトを閉じない方法はありませんか?    なければ出力を残す方法はありますか? 質問(2)    バッチファイルを毎回生成して、    そのバッチファイルをShellコマンドで実行すれば動くのかも知れませんが    他に良い方法はありませんか? よろしくお願いします。 私は、VB2010は初めて。 VB6で2個プログラムを作った程度です。 コマンドプロンプト関連(?)は初めてです。

  • パソコンを使ってマイコンとシリアル通信

    マイコンでソフトを開発してる組み込み系の技術者です。 例えば、PCからマイコンへ  UART, 9600bps, StopBit=1, LSBファースト、バイナリ通信 で送受信したいです。 PCから送信してマイコンからデータが返信されるのを確認したいです。 単純に送信して受信してだけでなく、 例えば、0x00を受信したら、次の送信を行い、 0x00以外なら再び同じ送信を行うなどのようなことがしたいです。 また、受信してから所定時間後に次の送信を行うなどです。 要するに、受信条件で次の送信をきりわけたいです。 例えば、VB2010だとある特定の数字を受信すると、停止コマンドとみなし、 通信が終了してしまうと聞いたことがあります。 また、VBだともろにソフトを組むことになり、そのソフト作成が大変そうです。 できるだけ簡単な記述で実現させたいです。 説明がうまくできなくてすいません。 ご存知の方、教えてください。

  • シリアル通信で0x00を送信したいのですが。

    こんにちは、VC++初心者です。 現在、下記サイトのプログラムをもとにシリアル通信用プログラムを作成しています。 http://www.takebay.net/~daigo-ao/paddlewiki.pl/title_A5B7A5EAA5A2A5EBC4CCBFAE2852532D3233324329A4C7C1F7BFAEA1A6BCF5BFAEA4F2B9D4A4A6A5D7A5EDA5B0A5E9A5E0.html 例えば、editboxに02 31 32 33 03と入力したら、0x02 0x31 0x32 0x33 0x03として送信するところまではできました。 ただし、00と入力したとき、0x00として送信することができません。 どうすれば0x00を送信できるか、ご教授お願いいたします。 m_editSend.GetWindowText()にて入手したstrSendのデータから、SPACEを除いて、 0xをつけてhexにしてから、Send()にて送信しています。 void CSerial2Dlg::OnBnClickedButtonSend() { CString strSend; CString strSendCMD; CString bw; int i, n, i2; unsigned int hex; m_editSend.GetWindowText(strSend); // ポート名を取得 char *buff = new char[strSend.GetLength()+1]; if(strSend.GetLength() == 0 || strSend == " "){ //送るものが無ければ終了 AfxMessageBox("送信するコマンドがありません。"); } else{ strcpy(buff, strSend); //editboxのデータをbuff[]へコピー i = 0; n = 0; bw = "\0"; while (buff[i] != '\n'){ if( buff[i] == ' ' || buff[i] == ':' || buff[i] == ',')//SPEACEorコロンorカンマをSKIPして送信する。 else{ bw += buff[i];//2文字ためる n++; } if(n == 2){ sscanf(bw, "%x", &hex); //bwに2文字溜まったら、hexに変換 strSendCMD += hex; bw = "\0"; //変換が終わったらClear n = 0; //カウントもリセット } i++; } m_serial->Send(strSendCMD, strlen(strSendCMD)); } delete [] buff ; //bufferの開放 } 下記のプログラムで、 WriteFileにて送信しています。 void CSerialCommunication::Send(LPCSTR str, DWORD strLength) { if (m_hComm == NULL) { AfxMessageBox("COMポートが開かれていません"); return; } // ** 送信! ** DWORD dwWrite; // COMポートに送ったバイト数 WriteFile(m_hComm, str, strLength, &dwWrite, NULL); }

専門家に質問してみよう