• 締切済み

シリアル通信におけるプログラム終了が遅い件

今、Visual Basic6.0でシリアル通信を行うプログラムを作成しています。完成後に実行させると思い通りに端末からのデータを表示してくれるのですが、[切断]といったポートを閉じる操作をしたときにプログラムが終了するまでに30秒から40秒ほどかかってしまいます。ソースを書き直して再度実行するなど、終了するたびに毎回同じくらいの時間がかかります。Windowsのハイパーターミナルでもデータの受信・表示ができる上、[切断]ですぐに終了するのですが、自作のプログラムではそうはいきません。解決方法をよろしくお願いいたします。

みんなの回答

  • takasebou
  • ベストアンサー率42% (61/144)
回答No.7

これは恐らく通信状況の問題のようですね。たぶん電文受信待ち状態で切断しようとした時に時間待ちが発生するという事ですね。 ちなみにタイマーを使ってはいけないという事ではないですよ。システムによっては、その方がいい場合もあるでしょうね。しかしタイマー処理よりも別の方法にした方がベターです。 コミュニケーションオブジェクトは、データが送信されてくると、OnCommイベントが発生しますから、そのイベントをもってデータの受信を行った方がいいと思います。 たぶん#1の方がいわれているようにタイムアウト待ちしているんだと思いますよ。 例えばURLのサイト等参考にしてみてください。参考に出来るソースもダウンロード出来るようです。 MSComm でGoogleなどで検索すれば、沢山この手のサイトは出てくると思いますので、そちらを参考にしながら進めるのがいいと思います。 がんばってくださいね。

参考URL:
http://speana-1.hp.infoseek.co.jp/vb/vb_5/vb_5.htm
nw_lab
質問者

お礼

いろいろお世話になりました。参考サイトをもとに、Oncommイベントで試してみたいと思います。ありがとうございました。

  • takasebou
  • ベストアンサー率42% (61/144)
回答No.6

Private Sub BtnEnd_Click() IF MSComm1.PortOpen = True Then MSComm1.PortOpen = False End if Unload Me End Sub とりあえず、こういった形にしてみてください。 なお一応私の方で同様のソースで試してみたところ、現象を再現出来ませんでした。実際にはこの他にソースがありませんか?

nw_lab
質問者

補足

遅くなりまして申し訳ございません。ソースに関しまして、補足させて頂きます。 -------------------------------------------------- Private Sub Form_Load() MSComm1.CommPort = 3 MSComm1.Settings = "9600,N,8,1" MSComm1.InputMode = comInputModeText If (MSComm1.PortOpen = False) Then MSComm1.PortOpen = True End If End Sub Private Sub BtnSrt_Click() Timer1.Interval = 5000 End Sub Private Sub BtnEnd_Click() Timer1.Enabled = False If (MSComm1.PortOpen = True) Then MSComm1.PortOpen = False End If Set Form = Nothing End Sub Private Sub Timer1_Timer() RichTextBox1.Text = MSComm1.Input End Sub ------------------------------------------------- takasebou様の1つ前のご回答の時に、通信にタイマーを使っていないかということでしたが、実は使っていたときのほうが安定しておりました。ですが、使わないほうがいいのかと思い、タイマーを使っていないソースでご返信をいたしました。ところが、上記のソースだとテキストボックスに受信内容が表示されます。終了時の問題はまだ未解決ですが、私のほうで[受信][終了]ボタンの間にタイマーをとめるための[切断]を作り、最初の1,2回は即終了するという良い結果を得ました。しかし、なぜかそれ以降、即終了することはなく、未だに40秒程経過するのを待たないとプログラムが終了しない状況でございます。 何度も申し訳ございませんが、よろしくお願い申し上げます。

  • takasebou
  • ベストアンサー率42% (61/144)
回答No.5

#2です とりあえずset Form = Nothingは消してみてください。Formとかコマンドボタンとかの実際に画面上に設置してるオブジェクトは別に解放しなくてもいいです。 Set obj = …… で設定したオブジェクトに関して解放してあげてください。あと終了ボタン押した時の処理は Unload Meで終了しませんか? Endステートメントは避けた方がいいです。 あとまぁ切断ボタンを作らなくても、終了ボタンを押した一連の流れの中で切断処理を行えばいいかとは思います。 private Sub cmdEnd_Click() a.close  ← ポートクローズ unload me ← フォームのアンロード End Sub こんな感じで。まぁ、たぶんこれくらいのプログラムだと使ったからどうという訳でもないですが、他と連携するようなログラムになってくると思わぬ動作を引き起こす可能性もあります。 で、肝心の速度が遅い件ですが、どうやら切断する時に切断処理に時間がかかっているようですね。 と、いう事は具体的なコードがないと判断が難しいです。 接続-通信-切断を実際のコードでどのように処理しているのでしょうか。通信に関しては、もしかしてタイマーでくるくる回していますか? その場合は先にタイマーを止めてみましょう。tmrObj.Enabled =False等。 後は具体的にコードをある程度書いていただかないと(一概にシリアル通信といっても、いろいろやり方があるので)、判断が難しいです。

nw_lab
質問者

補足

ご回答を受けまして修正した部分は元に戻して記載します。なにぶん初心者ですので、ソースには不十分な部分が多いかと思います。よろしくお願いいたします。 ------------------------------------------------------------ Private Sub Form_Load() MSComm1.CommPort = 3 MSComm1.Settings = "9600,N,8,1" MSComm1.InputMode = comInputModeText If (MSComm1.PortOpen = False) Then MSComm1.PortOpen = True End If End Sub Private Sub BtnSrt_Click() '受信内容の表示 RichTextBox1.Text = MSComm1.Input End Sub Private Sub BtnEnd_Click() End End Sub

  • takasebou
  • ベストアンサー率42% (61/144)
回答No.4

すみません、下で#1です。と書きましたが、#2ですの間違いでした(^^;

  • takasebou
  • ベストアンサー率42% (61/144)
回答No.3

#1です。 通信プログラムの前提として アプリ起動-接続-通信-切断-アプリ終了 というのは一連の流れとして、必ず実行しなくてはならない流れです。 ですので、切断せずにアプリを終了させようとすると通信を何とか続行しようとして時間がかかっている可能性がありますね。 ちなみにEndステートメントは強制的にプログラムを終了させるコマンドなので、あまり通常時に使用するのは望ましくないので使わない方が無難です。もっているオブジェクトを強制的に破棄するので、その時点でどのような動作をするかわからないからです。 どうしても必要な場合を除いて、開いているフォームを全てUnloadする事で終了させるようにした方が望ましいです。また何かオブジェクトや動的配列を使用していれば、そちらは解放(set obj = nothing や Erase a()等)してからUnloadする必要があります。

nw_lab
質問者

補足

度々申し訳ありません。ご回答を受けてプログラム中では、[受信]、[切断]、[終了]という3つのボタンを設け、[切断]にてポートクローズとSet Form = nothing をするようにしました。そして、[終了]でEndをするようにしてあります。受信後に[切断]を押すとマウスポインタが砂時計表示になり、フォーム上部に(応答なし)の表示が出てしまいます。数秒待てば[終了]を押すことが可能になりますが、やはり、切断から終了までの流れには時間がかかってしまう状況です。 よろしくお願いいたします。

  • takasebou
  • ベストアンサー率42% (61/144)
回答No.2

終了する時にまず接続を切ってから終了していますか?

nw_lab
質問者

補足

これはつまり、プログラムを終了させる前にポートを閉じる操作をすればいいということでしょうか?現状では、[終了]というボタン操作でEndするようにしているだけなので、ポートクローズしていない可能性が出てきました^^;

回答No.1

シリアル通信を、常時受信中にしていませんか? データの有無を確認してから受信しないと タイムアウトになるまで戻ってきません。

nw_lab
質問者

補足

Form_loadにおいて、ポート番号の指定・通信速度などの設定・テキスト受信モード設定・ポートオープンをさせています。それから[受信]をクリックした際にテキストボックスに受信データを表示させる仕組みなのですが、ある任意の時に[切断]を押して終了する場合に時間がかかってしまう状況です。なお、データは常に次から次へと新しいものが発生するため、データが無い状態にはならないものです。 補足として質問させて頂きますので、改めてよろしくお願いいたします。

関連するQ&A

  • シリアル通信について

    VB6にてシリアル通信プログラムを作成しましたが、データが受信できません。 ハイパーターミナルなら受信できて、一度ハイパーターミナルを使用すると、作成したプログラムでもデータが受信できるようになります。(再起動するとまたハイパーターミナルを使用するまで受信できません) 自作プログラムでなにか処理がたりないのでしょうか?

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

    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

  • LINUXでシリアル接続するには?

    LANスイッチ等のネットワーク機器の管理用のシリアルポートに、LINUXを接続したいのですが、どうやって端末にするのかがさっぱりわからず、結局また今日も結局諦めてWINDOWSのハイパーターミナルでつないでいます。 kermitというのを使うのでしょうか? それとも、WINDOWSハイパーターミナルのようなGUIがあるのでしょうか?

  • エクセルのマクロ(visual basicのプログラムを組む)を使ってハイパーターミナルにコマンド実行させる方法を教えてください

    エクセルのマクロ(visual basicのプログラムを組む)を使ってハイパーターミナルにコマンド実行させる方法を教えてください 私はハイパーターミナル(PC)と実験装置(EIA)を接続しデーターを得ています。 ここではハイパーターミナルにコマンドを入力することで装置(EIA)に操作を実行させています エクセルのマクロ(visual basicのプログラムを組む)をつかってコマンドボタンを押すだけで同一のPC上のハイパーターミナルにコマンドを入力させたいのですが、その方法を教えていただけるとありがたいです。よろしくお願いします プログラムについては知識が乏しいのですが、よろしくお願いします

  • エクセルとシリアル通信

    PICでシリアル通信利用して、ハイパーターミナルに温度を表示する装置を 作りました。これもしかして、直接エクセルに取り込めないんでしょうか。 そうすると、加工しやすくなるんですが。

  • VirtualBoxでのシリアル通信設定について

    VirtualBoxを使用したシリアル通信の設定方法について教えて下さい。 以下、やりたいこと及び、環境(設定)です。 【やりたいこと】 ホストOSとゲストOS間でシリアル通信を使用して、 データの送受信等をやりたいです。 【環境・設定】 ・VirtualBox ver.4.0.10 ・ホストOS WindowsXP SP2   通信ポート設定     COM1 有効     IRQ   04     I/O範囲 03F8~03FF   使用ソフト  ハイパーターミナル、SeriaDdebug ・ゲストOS Fedora8   通信ポート設定(VirtualBoxの設定→シリアル)     ポート1     シリアルを有効化にチェック     ポート番号 COM1(※COM2もやってみましたが、結果は変わりませんでした。)     IRQ     4     I/Oポート 0x3F8     ポートモード ホストデバイス     ポート/ファイルパス COM1     ※ポート2は設定していません。   使用ソフト minicom、自作アプリ ※上記条件でVirtualBoxのfedoraを立ち上げて、ホスト側でシリアル用ターミナルを 起動すると、ポートが開けません等のエラーログ(ポップアップ)が出ます。 設定方法、そもそものできる出来ない等のアドバイス、回答をお願い致します。 よろしくお願いします。

  • PICのシリアル通信のWIN_APIプログラムについて

    PICとPCとのシリアル通信の WIN_APIプログラムについてどなたかご存知の方は教えてください. 現状,API関数を用いて,シリアル通信をできるようにプログラムを作成したのですが,送信はできるのですが,受信データが"C0"をPICから送付しているのに,"FFFFFFFC0"と受信されてしまいます. 先の"FFFFFFF"をとるにはどうしたらいいでしょうか? 現状:受信プログラム // シリアルポートに対する書き込み(PICに送信命令) WriteFile(hCom, w_com_Buf,lstrlen(w_com_Buf), &n, 0 ); // シリアルポートに対する読み込み ReadFile(hCom, s_com_Buf,1, &n, 0 ); mikroC上のUSARTターミナルでは送受信は適正で, 上記のプログラマで 送信はPIC側で受信していることは7SEGを使って確認しています. しかし,PC側では, s_com_Buf[0]には,"C0"が入ったり,"FFFFFFC0"が入ったりします. PICは現状,多チャンネルAD変換をしているため, 送信に対する受信データのやり取りができなくて困っています. どなたか先生教えてください.

  • シリアル通信プログラム(受信)について

    現在、シリアル通信をする(受信のみ)プログラムを作成しています。 接続先は1秒ごとに10バイトのデータを自動で送信してきます。 現段階でPC側でデータを受信できることは確認できました。 しかし、受信データが文字化け(出力結果が{や■などがでています)しており、その原因がわかりません。 どこが問題なのか教えていただけないでしょうか? また、接続先からは10バイトのうち最初の2バイトは固定の値(0x2b,0x22)がでてくるはずなのですが、それもでてきていません。これも文字化けで見えていないだけでしょうか? 文字化けしても周期的に固定の値に対応した文字がでてくるものだと思ったのですが、でてきていません。 (ソースで50バイトまでみているのはこの周期性を確認するためです) シリアル通信を初めてさわるので、考え方自体間違っているかもしれませんが 配列pszBufに1つずつ、受信された1バイトのデータが格納されていると思っています。 個人的にはprintfでの表記(%cがいけない?)に間違いがあるかと疑っています。 ご回答よろしくお願いいたします。 (環境) Visual C++ 2008 (C/C++) (シリアルポート設定) ボーレート 9600bps パリティ   なし ストップビット 1 データビット 8 (ソース) ※ポートの設定は省略。受信部のみ記述 HANDLE hComm; DWORD dwErrors; COMSTAT ComStat; char pszBuf[1024]; DWORD dwRead; ClearCommError(hComm, &dwErrors, &ComStat); ReadFile(hComm, pszBuf, 50, &dwRead, NULL);  //50バイトまでデータを取得 for(int i=0;i<50;i++){ printf("%c\n",pszBuf[i]); } (参考URL) http://www.geocities.jp/terukat/_geo_contents_/win/comm.html

  • USB通信について

    RS-232 を使ったシリアル通信の場合、WINDOWSにハイパーターミナルが装備してあるので、 たとえばPICからデータを送ったりする場合簡単にできます ところでUSBを使ってデータを送ったりする場合はどうやってやるんでしょうか。 ハイパーターミナルに相当するソフトとかあるんでしょうか、おしえてください。

  • TeraTerm シリアル通信の垂れ流しデータ取得

    ターミナルソフト「TeraTerm」の「マクロ」を使用して、RS-232C 経由でシリアルポートに接続された端末機器(測定器)と通信するソフトウェアを開発中です。 「マクロプログラム」の中から「あるテキストデータ」を送信(sendln)すると、端末機器からは時々刻々の測定値データを1行ごとに連続して垂れ流しで返してくれる。 この垂れ流れてくるデータを取り込んで、ある種の判断処理プログラムを制作したいのだが、この手の言語に不慣れなこともあって、相談させてください。 一般的な場合、コマンド「recvln」を発行するとシステム変数「inputstr」に受診データが格納されるのだけど、今回のような垂れ流されるデータのの場合も同じようなことをするのだろうか? コンソールに時々刻々と垂れ流しデータが表示されているのだから、何か重複してしまう操作のように思えてならない。 もっとスマートな処理方法があるように思えてならない。 なるべくリアルタイムに近い処理をさせたいので、無駄な処理は省きたい。 ご教授やアドバイスをいただければ助かります。

専門家に質問してみよう