- ベストアンサー
VB2005でWin32APIを用いてRS-232CのRTS信号を、データ送信中だけHIGHにさせるプログラムを作成中です。
- 質問者はVB2005でWin32APIを使ってRS-232CのRTS信号をデータ送信中だけHIGHにさせるプログラムを作成中であり、上手く動作しない問題に直面している。
- 質問者はCreateFile()関数を使ってCOMポートを開き、EscapeCommFunction()でRTS信号をHIGHに設定し、WriteFile()関数でデータを送信しているが、WaitCommEvent()関数がデータ送信完了を待たずに抜けてしまうという問題が発生している。
- 質問者はWaitForSingleObject()を使ってイベントハンドラがシグナル状態になるのを待つが、タイムアウトの値を設定するとうまく動作しないという問題が発生している。解決策を求めている。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
>SetCommEvent()関数で"EV_TXEMPTY"イベントマスク 多分 SetCommMask のTypeミスですよね? 実際送信監視をしたことはないのと扱ったのが かなり昔の話なので間違ってる可能性ありますが (更にVBは知りません) (6)でGetLastErrorで戻りが ERROR_IO_PENDING になってませんか? その場合送信中って判断しないといけなかったような http://msdn.microsoft.com/ja-jp/library/cc429842.aspx 以下余談 本来の目的が良くわからないのですがもしフロー制御などのために RTS信号使うのであればわざわざ自分でコントロールする必要ないはずです (フロー制御としてRTSCTSを選択すれば勝手にやってくれるはず)
その他の回答 (6)
- Hayashi_Trek
- ベストアンサー率44% (366/818)
横から口出しさせてもらいます、 >データ送信完了後20ミリ秒以内にRTS信号をLOWにしないと、 >正しく通信できないようになっています。 これは非常に難しいです。 なぜかというと、 SetCommEvent()関数の"EV_TXEMPTY"イベントは 「送信バッファから最後のデータを送信した」ときに発生しますが あくまでも、送信バッファが空になっただけで、送信が完了している保証が無いのです。 "EV_TXEMPTY"イベントからどのくらいの待ち時間が必要かはPC毎に異なる可能性があります。 ※送信バッファのデータが1バイトずつUARTチップに送られるが、 ※UARTチップ自体がバッファを持っているので、 ※送信バッファが空になっても送信は続いています。
お礼
助言、ありがとうございます。 EV_TXEMPTYイベントでは、微妙なタイミングが難しいのですね。 最終的に、RtsControlに”Toggle”を指定することで、やりたい事が実現できました。
- koi1234
- ベストアンサー率53% (1866/3459)
連投になりますがURL書いたほうが早そうなので 以下URL見てて ひょっとしたら目的はRS485 とかですかねなんて思いました (半2重通信?) 余りに昔で当時私が使っていたWEBは消えてなくなってましたが 検索かけたところ別のところにありました(こっちが本家か?) Delphiソースになりますが以下ソースを参考にしてみてはどうでしょう (#5で書いた人様のコンポーネントってのがまさにこれのことです) http://wiki.fdiary.net/apollo/?Phi%3A%3ACommX ※ Delphi(Pascal)ソースですが使ってるのはWin32APIなので それほど悩まなくても読めるのではないかと思います
お礼
koi1234さん 色々ありがとうございました。 最終的に、"EV_TXEMPTY"イベントを使用せず、DCB構造体のRtsControlを"Toggle"にセットすることで 要望通りの動きをオシロスコープにて確認できました。 以前もToggle指定を試していましたが、正しい使い方は、DCB構造体内の 「ビットフィールド」で設定する、ということでした。これを知らずに BYTE変数で指定していました…。 本当にありがとうございました。 大変勉強になりました。
補足
その通り、RS-485とRS-232C両方を備えたデバイスとパソコン間で通信しようとしています。 下にも書かせていただいた通り、パソコン側はデータ送信中にRTS信号をHIGHにして、 データ送信完了後20ミリ秒以内にRTS信号をLOWにしないと、正しく通信できないようになっています。
- koi1234
- ベストアンサー率53% (1866/3459)
>ピクリとも動きませんでした・・・。 ここら辺は補足に書いたとおりデータ送信時にHIGHにするという挙動とは 異なる可能性があります (信号の極性の話もそうですが変化タイミングは間違いなく違います) 確認する為には特殊な条件環境を構築しないと確認できないので 簡単なテストが出来ないのですがテスト環境の問題で変らない と思い込まれているだけではないかと思います(そうじゃないならごめんなさい) # 送信側はデータ送り続け受信側はデータ受信しないような通信環境を # 作らないと確認できません # 通信ソフト動かすと普通は受信動作してしまうのでなかなか確認できません 最終的に行いたいのはフロー制御としての信号制御処理なのでしょうか? 今、人様が作った通信プログラムのコンポーネント処理を見ていたのですが (それも送信バッファイベントは見てませんでした & 言語はdelphi) 受信時 ERROR_IO_PENDING だった時に GetOverlappedResultで TRUE になるまでループしてますね 送信でも同様な処理が必要なのかもしれません そういえば昔 #4さんの言われてるような型の違いで 動かなくなるってのもあったのを思い出しました (どの言語でも似たような話があるのかと再認識しました) 問題になるのは Create時の 戻り値ぐらいだったような気もしますが いかんせん昔の話で忘れています
補足
本当に色々ありがとうございます。 ご紹介いただいたソースを見ました。 確かに、"GetOverlappedResult()"でTrueになるのを待っている処理になっていますね。 ※"WaitCommEvent()"は使用していないようですね…。 明日、早速試してみたいと思います。 > 確認する為には特殊な条件環境を構築しないと確認できないので > 簡単なテストが出来ないのですがテスト環境の問題で変らない > と思い込まれているだけではないかと思います(そうじゃないならごめんなさい) > # 送信側はデータ送り続け受信側はデータ受信しないような通信環境を > # 作らないと確認できません > # 通信ソフト動かすと普通は受信動作してしまうのでなかなか確認できません テスト環境では、通信先デバイスにはRS-232Cケーブルを接続せずに、パソコンから伸びたRS-232Cケーブルの先にピンを立て、そこにオシロスコープで当たって信号をチェックしています。 > 最終的に行いたいのはフロー制御としての信号制御処理なのでしょうか? 最終的には、通信先デバイスとデータの送受信を行いたいのですが、そのデバイスの通信仕様(ルール)で、パソコン側からデータを送信する際にはRTS信号をHIGHにし、データ送信完了後20ミリ秒以内にRTS信号をLOWにしなければ、正しく通信できません。
- sknbsknb2
- ベストアンサー率38% (1158/3030)
VB6以前のLong型はVB2005ではInteger型になっているので、Win32APIを使う場合はこれを書き換えないと正常動作しませんが、お使いのプログラムでは変更済みでしょうか?
補足
sknbsknb2さん ご回答ありがとうございます。 データ型の宣言が違っているのはネットで調べて理解しております。 基本的に、「http://www.pinvoke.net/」で関数の型、構造体などを調べてコーディングしています。 この宣言、または関数の呼び出し順が間違っているのかもしれません…。
- koi1234
- ベストアンサー率53% (1866/3459)
#2 補足 あくまでフロー制御としてハードウエア信号を使う場合RTS/CTSで出来る という話であって(XON・XOFFはソフト的なフロー制御) 質問者さんのやろうとしている?データ送信中だけHIGHにさせる とは挙動が異なるはずです (#1に書いたように目的が良くわからなかったのであくまで余談として書きました)
補足
ありがとうございます。 とてもWin32APIをC#で使うのはとても難しいです…。 そもそも、関数宣言が誤ってる/関数の呼び出し順が誤ってるような気もします…。
- koi1234
- ベストアンサー率53% (1866/3459)
>その後、While文で"WaitForSingleObject()"を繰り返し呼び出し、 >シグナル状態になるのを待っているのですがこのWhile文を抜けることができません。 合ってるかは判りません(↑が記載ミスではないとして) WaitCommEventが(ERROR_IO_PENDINGで)エラーになっているのですから WaitForSingleObjectを呼び出してもダメでしょう 繰り返すならWaitCommEventを繰り返すべきでは? >何かの設定をすれば、プログラム側からRS-232Cへ >データ送信している間にだけ、RTS信号をHIGHにすることが出来る (実際の信号レベルまで確認したわけではありませんが) フロー制御で使いたいということであればそういうことです (フロー制御にはそれ以外にもXON/XOFFも可能です 併用も可) DCB構造体の設定を行うことでその辺りの設定が行えます 書かれてませんが既に通信レートなどの設定で使ってる気がします 標準のまま何も設定していなくて動いているかもしれませんが 本来アプリ側できちんと設定すべきです http://msdn.microsoft.com/ja-jp/library/cc429121%28v=MSDN.10%29.aspx 御存知かもしれませんが↑に通信関連関数一覧の説明があるので BuildCommDCB/GetCommState/SetCommState 辺りを見てください
補足
色々ありがとうございます。 > WaitCommEventが(ERROR_IO_PENDINGで)エラーになっているのですから > WaitForSingleObjectを呼び出してもダメでしょう > 繰り返すならWaitCommEventを繰り返すべきでは? WaitCommEvent()繰り返しも試してみましたが、Whileループから抜け出せません・・・。 ※以下、ソースコード抜粋。 途中でVB.NETからVC#に移植して試しておりますので、VC#のソースになっていますが、あしからずご了承頂けますか。 uint dwEvent; //// RTS信号 HI EscapeCommFunction(hSerialPort, (uint)ExtendedFunctions.SETRTS); //// データ送信 WriteFile(hSerialPort, snd_buf, (uint)(len), out (uint)lrc, ref hOvr); // イベント作成 hOvr.EventHandle = CreateEvent(IntPtr.Zero, true, false, null); // 送信エンプティのイベントを設定 SetCommMask(hSerialPort, EV_TXEMPTY); // イベント=送信バッファエンプティ待ち WaitCommEvent(hSerialPort, out dwEvent, ref hOvr); while (true) { WaitCommEvent(hSerialPort, out dwEvent, ref hOvr); if (dwEvent == EV_TXEMPTY) { break; } } > DCB構造体の設定を行うことでその辺りの設定が行えます DCB.RtsControlというのがありましたので、それを"Enable"、"Toggle"、"Handshake"など試してみましたが、ピクリとも動きませんでした・・・。 DCB構造体に対しては、仰るとおり、ボーレートやデータビット長などの設定を行っております。
補足
ご回答ありがとうございます。 仰る通り、GetLastErrorの返り値は "ERROR_IO_PENDING"です。 この返り値は、正しいのだと思うのですが、 その後、While文で"WaitForSingleObject()"を繰り返し呼び出し、 シグナル状態になるのを待っているのですがこのWhile文を抜けることができません。 ※"WaitForSingleObject()"の返り値が"0"になれば、While文を抜けるようコーディングしています。 > RTS信号使うのであればわざわざ自分でコントロールする必要ないはずです > (フロー制御としてRTSCTSを選択すれば勝手にやってくれるはず) これは、何かの設定をすれば、プログラム側からRS-232Cへデータ送信している間にだけ、RTS信号をHIGHにすることが出来る、ということでしょうか??