出産前後の痔にはご注意!

VB.netで、シリアル通信のタイムアウト処理について

http://msdn.microsoft.com/ja-jp/library/7ya7y41k …
このサイトのコードを、参考にしています。
------------------------------------ここから
Dim com1 As IO.Ports.SerialPort = Nothing
Try
com1 = My.Computer.Ports.OpenSerialPort("COM1")
com1.ReadTimeout = 10000

Catch ex As TimeoutException
returnStr = "Error: Serial Port read timed out."
Finally
If com1 IsNot Nothing Then com1.Close()
End Try

------------------------------------ここまで

この方法ですと、タイムアウトが発生したらポートを閉じるようですが、これを、送信したシリアルのデータを再度、送信させたいと思います。
そして、何度かリトライを掛けた後に、やっぱり駄目だったときに
ポートを閉じたいと思います。

どんな方法がありますか?

参考になりそうなサイトなどがありましたら、教えていただけませんか。
以上、よろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

タイムアウトはWrite/Read(送受信)系メソッドで


発生します。そのメソッドをTry~Catchブロックで
ハンドリングしないと意味ないでしょ。
掲題のプログラムはポートを開いて、タイムアウトの
時間を設定しただけですから、送受信していません。
    • good
    • 0
この回答へのお礼

ありがとうございます。

長らくお付き合いしていただきまして、感謝しております。
何とか解決できそうです。

お礼日時:2010/07/28 09:06

あぁ、そういうやり方ですか。


それだと、Private Sub ButtonRsStart_Clickでは
仕込みするだけですからタイムアウトになりません。
だって、Readしてませんからね。タイムアウトは読み
込みを始めてから完了するまでの制限時間です。
よって、このメソッドではOpenメソッドの失敗で例外が
発生するくらいでしょうか。

Private Sub SerialPort1_DataReceived
こちらの方でタイムアウト時の処理を記述すべきです。

それにしても、何所にも「送信」している箇所が無い
ように見えますが、大丈夫なんでしょうか?
    • good
    • 0
この回答へのお礼

ご返答、ありがとうございます。


>Private Sub SerialPort1_DataReceived
>こちらの方でタイムアウト時の処理を記述すべきです。

と、言う事は、タイムアウトが発生したら、Private Sub SerialPort1_DataReceivedの中で処理出来るのでしょうか?


>それにしても、何所にも「送信」している箇所が無い
>ように見えますが、大丈夫なんでしょうか?

これは、別口で「送信」ボタンを設けているからです。
つまり、仕込み部、送信部、受信部という構成にしています。

お礼日時:2010/07/23 14:38

次のように考えたら如何でしょう。


(1)ポートを開く。この時に例外が発生したら終了する。
(2)以下の(3)~(5)を既定の回数繰り返す。
(3)データを送信する。
(4)データを受信する。読み込めたらループを抜ける。
(5)タイムアウトなら(3)から繰り返す。
(6)ポートを閉じる。

Try
    com1 = My.Computer.Ports.OpenSerialPort("COM1")
    com1.ReadTimeout = 10000
    For I As Integer = 1 To 5
        Try
            returnStr = con1.ReadLine()
            Exit For
        Catch ex As TimeoutException
            returnStr = "Error: Serial Port read timed out."
        Catch ex As Exception
            returnStr = ex.Message
            Exit For
        End Try
    Next
    com1.Close()
Catch ex As Exception
    returnStr = "Error: Serial Port open failed."
End Try

この回答への補足

早速の御解答を戴きまして、ありがとうございます。

私の説明不足で申し訳ございませんが、私が書いたプログラム構造は次のようになっています。

'初期設定&ポートを開く
Private Sub ButtonRsStart_Click(ByVal sender ・・・) Handles ButtonRsStart.Click

With SerialPort1
Try '例外処理のはじまり
If .IsOpen = True Then 'ポートはオープン済み
MessageBox.Show("すでに" & .PortName & "は接続されています。", "エラー",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If

.PortName = PORTNUM.Text 'オープンするポート名を格納
.Open() 'ポートオープン
.DiscardInBuffer() '入力バッファを、初期化する
.DiscardOutBuffer() '出力バッファを、初期化する
.ReadTimeout = 1000 'Time out (ms)


Catch ex As TimeoutException
'Timeout 例外処理
MessageBox.Show(ex.Message, "Error: Serial Port read timed out.", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End With
End Sub


'受信イベントが発生したときの処理を記述します
Private Sub SerialPort1_DataReceived(ByVal sender ・・・) Handles SerialPort1.DataReceived


Try

'1フレーム分を、読み出す。
ReceivedData = SerialPort1.ReadLine

'受信処理をする。

Catch ex As Exception
ReceivedData = ex.Message
End Try

End Sub
--------------------------- ここまで

このやり方ですと、タイムアウトのとき、
Handles SerialPort1.DataReceived の受信イベントが発生しなくて
SerialPort1_DataReceived の処理をしないのではないでしょうか?

もし、そうなら、次のように
Private Sub SerialPort1_ErrorReceived() Handles SerialPort1.ErrorReceived
(エラー処理)
End Sub
といった具合に、処理を分ければいいのでしょうか?

長くなりましたが、何卒、御教示ください。

補足日時:2010/07/21 17:21
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC# シリアル通信でデータ受信時の欠損について

Visualstudio 2013 を使用して C# で開発を行っています。

SerialPort Classを使用してデータの送受信をするプログラムを作成しているのですが、
非同期でデータを受信する際にどうしてもうまくデータを取得出来ません。

5Byteのデータは正常に取得できるのですが、
その直後にくる40Byteのデータは、真ん中あたりの10数Byteや最後の10数Byteしか取れません。


serialPort.DataReceived に登録したイベント関数の中身です。

--------------------------------------------------------------------------------------
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
bytesRead = 0;
// Initialize a buffer to hold the received data
byte[] buffer = new byte[this.serialPort.ReadBufferSize];

try
{
bytesRead = this.serialPort.Read(buffer, 0, buffer.Length);
if (true == serialPort.IsOpen)
{
serialPort.DiscardInBuffer();//受信バッファをクリアする
}

}
catch (Exception ex)
{
DataLog.Exception(ex);
}

//派生クラス用の処理
DeviceClassEventArgs _DeviceClassEventArgs = new DeviceClassEventArgs(buffer, bytesRead);
DeviceClassEvent(this, _DeviceClassEventArgs);
}
--------------------------------------------------------------------------------------

ネットの情報を参考に、
ReceivedBytesThreshold の値を期待するデータ量に逐一変えることで
とりあえず正常に取ることが出来たのですが、これでいいのでしょうか?
期待するデータ量がわからなかった場合は使えないのかなとも思います。

データが欠損してしまう理由、
上記の対処法以外の一般的な対処法など有りましたら教えて下さい。

その他参考になるページ等ありましたら教えていただけると大変助かります。

Visualstudio 2013 を使用して C# で開発を行っています。

SerialPort Classを使用してデータの送受信をするプログラムを作成しているのですが、
非同期でデータを受信する際にどうしてもうまくデータを取得出来ません。

5Byteのデータは正常に取得できるのですが、
その直後にくる40Byteのデータは、真ん中あたりの10数Byteや最後の10数Byteしか取れません。


serialPort.DataReceived に登録したイベント関数の中身です。

-------------------------------------------------------------------------------...続きを読む

Aベストアンサー

DataReceivedイベントが発生したときでも、
シリアルポートへの受信はまだ継続している可能性があるので
不用意にバッファクリアしてはいけない。
非同期の受信処理は、何かと難しいのです。

private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  bytesRead = 0;
  // Initialize a buffer to hold the received data
  byte[] buffer = new byte[this.serialPort.ReadBufferSize];

  try
  {
    //bytesRead = this.serialPort.Read(buffer, 0, buffer.Length);
    //if (true == serialPort.IsOpen)
    //{
    // serialPort.DiscardInBuffer();//受信バッファをクリアする
    //}

    // 受信バッファにデータがなくなるまで繰り返し読込む
    while (true)
    {
      if (0 == serialPort.BytesToRead)
      {
        break;
      }
      buffer[bytesRead] = (byte)serialPort.ReadByte();
      bytesRead++;
      System.Threading.Thread.Sleep(0);

      // シリアルポートの受信バッファには、
      // ・必要なブロックの途中から受信している。
      // ・次のブロックの先頭部分も受信されている。
      // 可能性があるので、ここで必要なブロックだけRead()できたことを確認する。
      if (必要なブロックが正常に読めたか確認する関数())
      {
        break;
      }
    }
  }
  catch (Exception ex)
  {
    DataLog.Exception(ex);
  }

  //派生クラス用の処理
  DeviceClassEventArgs _DeviceClassEventArgs = new DeviceClassEventArgs(buffer, bytesRead);
  DeviceClassEvent(this, _DeviceClassEventArgs);
}

DataReceivedイベントが発生したときでも、
シリアルポートへの受信はまだ継続している可能性があるので
不用意にバッファクリアしてはいけない。
非同期の受信処理は、何かと難しいのです。

private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  bytesRead = 0;
  // Initialize a buffer to hold the received data
  byte[] buffer = new byte[this.serialPort.ReadBufferSize];

  try
  {
    //bytesRead = this.serialPort.Read(buffer, 0, buffer.Le...続きを読む

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

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

ツールボックスの「Serial Port」を使っています。
送信までは難なくできたのですが、受信が旨くいきません。
参考にしたサイトは、
http://msdn.microsoft.com/ja-jp/library/cc720852.aspx です。

これを実行すると、受信が出来ないだけでなく、フリーズしてしまいます。

どうやったら、受信できるのでしょうか?

Aベストアンサー

受信データが、
STX(&H02)とETX(&H03)には挟まれた形式のテキスト文字になっている。
エラーチェックのBCCは付加されない。
という仕様ならば
ポートをOpenした直後に
SerialPort1.NewLine = Chr(3)
とすれば良い。
受信したデータの先頭1文字がSTXの場合に正常なデータと判断できます。

QSerialPortのDataReceivedイベントについて

Visial Basic 2005 にて SerialPort コンポーネントを使ったアプリを作っています。
当初、Microsoft のサンプルを参考に

SerialPort1.ReadLine

でデータを受信していたのですが、この方法だとバッファ内から再度同じデータを受信してしまうらしく、新しいバッファからデータを受信しないとイベントが発生する毎に古いデータを読み取ってしまいます。

そこで調べていたところ、Microsoft のフォーラムで以下のような Visual C# のソースを見つけました。

(以下引用)
> if (serialPort1.BytesToRead > 0)
> {
> // 受信バッファからデータを取得
> byte[] b = new byte[serialPort1.BytesToRead];
> Read(b, 0, b.Length);
> }

まだ Visial Basic 初心者なもので Byte 型の扱い方や上記ソースは Visial Basic でどのように書けばよいのかわかりません。
どなたかご教授ください。
よろしくお願いいたします。

Visial Basic 2005 にて SerialPort コンポーネントを使ったアプリを作っています。
当初、Microsoft のサンプルを参考に

SerialPort1.ReadLine

でデータを受信していたのですが、この方法だとバッファ内から再度同じデータを受信してしまうらしく、新しいバッファからデータを受信しないとイベントが発生する毎に古いデータを読み取ってしまいます。

そこで調べていたところ、Microsoft のフォーラムで以下のような Visual C# のソースを見つけました。

(以下引用)
> if (serialPort1.BytesToRe...続きを読む

Aベストアンサー

こんにちは、もう解決しているかもしれませんが。
ReadLineのヘルプには、
入力バッファ内の NewLine 値まで読み取ります
と記載してあります。Framework2.0からの機能なんですね。

私の場合、データ受信後その内容により返事を返すまでの間
次のデータを受信することは無い場合が多いので
DataReceivedイベントでSerialPort.Readを利用しています。
ReadLineは使用したことが無いのでわかりませんが
Readの場合、読み込んだデータがバッファに残っているということはありません。

QVisual Basic でのコードをASCII変換、16進変換したものを元に戻す方法を教えてください

string(9)のエリア"Aa1アあa "の文字を1文字ずつASCII変換して、16進変換し、string(18)のエリアに格納します
すると"416131B182A08281202020"と変換されます
(一文字ずつ Hex(Asc(Buf))を使用しました)

逆に、"416131B182A08281202020"を"Aa1アあa "に戻したいのですが、
どのような関数を使えばよいのかわかりません。
困っています。教えてください。よろしくお願いいたします。

Aベストアンサー

VB既存の関数ではできないと思うので、自分で関数を作るなりしてください。

ヒントです。
ASC関数により変換された2バイト文字(シフトJIS)の1バイト目は81~9FおよびE0~FC(すべて16進)になります。
16進数から10進数に戻すには、頭に"&H"をつけます。(&H82A0 = 「あ」のシフトJISコード)
文字を数字に変換するのはVal関数、数字(文字コード)から文字に変換するのはChr関数です。

QCloseとDisposeの違い

みなさまこんばんわです。よろしくお願い申し上げます。

VB.NET 2008でコーディングしています。
CloseとDisposeの違いについて教えていただきたいのです。

これらのメソッドは、開いたファイルを閉じるときなどにも使いますが、今回お尋ねするのは、フォームを閉じるとき、しかも、自ら呼び出すとき(Me.Close() と、Me.Dispose() )のみに限ったこととしてお話しさせていただきます。

たとえば、ShowDialog() で呼び出したフォームは、そのフォーム内でMe.Close() しても、プロセスは残り、たとえば、タイマーコントロールのイベントに記述していますと、それは実行され続けます。

これを防ぐために、Me.Dispose() を使います。すると、きれいにプロセスは終了し、イベントは発生しない模様です。

そこで、「フォームを閉じる」意味のMe.Close() をすべてMe.Dispose() に変えてしまいました。確実にプロセスを破棄出来ると思ったからです。Webで調べると、違いは「再利用できる、できないの違い」という答えがありましたが、それはきっと、ファイルやオブジェクトのことで、フォームの場合は、再びShowまたはShowDialogで表示させることは可能でしたので、特に問題は感じていませんでした。

ところが、アプリケーション設定で、「最後のフォームを閉じるとき」にアプリケーションがシャットダウンする設定になってるのに、シャットダウンしてくれないことが起こりました。調べてみると、Me.Dispose() が原因。Me.Close() に変えるとうまくいきました。

わけわからなくなってきました。。。

ちなみに、その残ったフォームは、スタートアップフォームであり、別のフォームからShowまたはShowDialogメソッドで呼び出したものではありません。

ここで4つの仮説を立ててみました。

1. ShowDialogで呼び出したフォームは、Me.Dispose()、Showで呼び出した、あるいは、スタートアップフォームは、Me.Close() すれば破棄できる

2. ShowDialogで呼び出したフォームは、Me.Dispose()、スタートアップフォームは、Me.Close()、Showで呼び出したフォームは、どちらでも、破棄できる

3. 呼び出し方ではなく、別の要因が存在する

4. 併記する必要がある場合がある

Me.Close()
Me.Dispose()

または、

Me.Dispose()
Me.Close()



どれが正しいのでしょうか?どなたがご存じの方がいらっしゃいましたら、ご教授いただけませんでしょうか? どうぞよろしくお願い申し上げます。ありがとうございました。

みなさまこんばんわです。よろしくお願い申し上げます。

VB.NET 2008でコーディングしています。
CloseとDisposeの違いについて教えていただきたいのです。

これらのメソッドは、開いたファイルを閉じるときなどにも使いますが、今回お尋ねするのは、フォームを閉じるとき、しかも、自ら呼び出すとき(Me.Close() と、Me.Dispose() )のみに限ったこととしてお話しさせていただきます。

たとえば、ShowDialog() で呼び出したフォームは、そのフォーム内でMe.Close() しても、プロセスは残り、たとえば、...続きを読む

Aベストアンサー

Me.Close()
Me.Dispose()
は根本的に違うものです。

formについて、Close()メソッドはフォームの表示を終了させるメソッドです。

ほかのクラスも同様。すべてのDispose()メソッドについて、これはインスタンスの破棄を明示的に行うものです。

>再利用できる、できないの違い

Dispose()はインスタンスが破棄されるため、再びコンストラクタを用いて、インスタンスを生成しないいけません。

一方Close()はインスタンスが残っているので、それを利用することができます。

>1. ところが、アプリケーション設定で、「最後のフォームを閉じるとき」にアプリケーションがシャットダウンする設定になってるのに、シャットダウンしてくれないことが起こりました。調べてみると、Me.Dispose() が原因。
Me.Close() に変えるとうまくいきました。

通常はどちらでもうまくいきます。

>2. ShowDialogで呼び出したフォームは、Me.Dispose()、スタートアップフォームは、Me.Close()、Showで呼び出したフォームは、どちらでも、破棄できる

ShowDialogの場合は、メソッド内部で、ハンドルが破棄されているため、Close()メソッドの際にDispose()メソッドが呼び出されます。

>3. 呼び出し方ではなく、別の要因が存在する

そう思います。

>4. 併記する必要がある場合がある

インスタンスを明示的に破棄したほうがよい場合は多く存在します。
Disposeが使えるメンバはIDisposableをインターフェースとして持っているメンバです。
これらのメンバは、外部とのやり取りを行うものが多くあります。
たとえばSQLClientに含まれるようなメンバです。

外部とのコネクションを確実に破棄を保障してほしいなどという場合がありますよね、このようなときに使用します。

Using構文を使用するのとまったく同じ理由になります。
正確にはUsing構文を使用できるメンバには条件があります、IDisposableをインターフェースとして持っているメンバに限るというものです。

ほかにもガーベージコレクタによるファイナライズを伴うかどうかという違いがあります。
Disposeの場合はファイナライズが同時に行われるため、使用していたメモリ空間を開放することができます。

上記のような理由により、
Me.Close()
Me.Dispose()
は両方書いたほうがよいと思います。

蛇足ですが、
Me.Dispose()
Me.Close()
はエラーになります。
Me.Dispose()により、Me本体(インスタンス)は削除されてしまいます。
存在しないMeに対してCloseメソッドを要求することはできないためです。

Me.Close()
Me.Dispose()
は根本的に違うものです。

formについて、Close()メソッドはフォームの表示を終了させるメソッドです。

ほかのクラスも同様。すべてのDispose()メソッドについて、これはインスタンスの破棄を明示的に行うものです。

>再利用できる、できないの違い

Dispose()はインスタンスが破棄されるため、再びコンストラクタを用いて、インスタンスを生成しないいけません。

一方Close()はインスタンスが残っているので、それを利用することができます。

>1. ところが、アプリ...続きを読む

QVB2010で、シリアル通信をするには

VB2010で、シリアル通信をするには

シリアルポートをopenしようとすると、エラーで弾かれてしまいます。
どのように対処したら良いですか?

使っているソースコードは、下記の通り。

Private Sub ButtonRsStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRsStart.Click
Try '例外処理のはじまり
If SerialPort1.IsOpen = True Then 'ポートはオープン済み
MessageBox.Show("すでに" & SerialPort1.PortName & "は接続されています。", "エラー",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If
SerialPort1.PortName = "COM1" 'オープンするポート名を格納
SerialPort1.Open() 'ポートオープン
PORT_STATE.Text = "OPEN"
Catch ex As Exception '例外処理
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

End Sub
---------------

エラーが発生する場所は、「Catch 」になります。
エラーメッセージは、「ポート 'COM1' へのアクセスが拒否されました。」です。

何が原因なのか、さっぱり分かりません。
ヒントになりそうな解答を頂けないでしょうか?

VB2010で、シリアル通信をするには

シリアルポートをopenしようとすると、エラーで弾かれてしまいます。
どのように対処したら良いですか?

使っているソースコードは、下記の通り。

Private Sub ButtonRsStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRsStart.Click
Try '例外処理のはじまり
If SerialPort1.IsOpen = True Then 'ポートはオープン済み
MessageBox.Show("すでに" & SerialP...続きを読む

Aベストアンサー

> どのアプリが「COM1」を、使っているのか判る方法は在りますか?

私も知りませんが、デバイスマネージャでモデムのデバイスのプロパティを見て、COM1になっているかどうかですね。

私のマシンではモデムはCOM3になっていますが、設定の変更をすればCOM1にすることもできますので。

あるいはデバイスマネージャで通信関係らしきデバイスのプロパティを調べてみる位しか思いつきません。

ちなみに、私のマシンではデバイスマネージャで「ポート(COMとLPT)」を見ると、COM1もCOM3
も表示されません。
モデムを見るとCOM3になっています。

COM1を指定してプログラムを動かすと「ポート 'COM1' は存在しません。」と表示します。

COM3を指定すると正しくオープンできます。

COM3を他の通信ソフトでオープンしておいて、COM3を指定してプログラムを動かすと「ポート 'COM3' へのアクセスが拒否されました。」と表示します。

この結果から推測すると、xcode_15さんのマシンはCOM1を他のソフトが使用しているということになります。

> どのアプリが「COM1」を、使っているのか判る方法は在りますか?

私も知りませんが、デバイスマネージャでモデムのデバイスのプロパティを見て、COM1になっているかどうかですね。

私のマシンではモデムはCOM3になっていますが、設定の変更をすればCOM1にすることもできますので。

あるいはデバイスマネージャで通信関係らしきデバイスのプロパティを調べてみる位しか思いつきません。

ちなみに、私のマシンではデバイスマネージャで「ポート(COMとLPT)」を見ると、COM1もCOM3
も表示されません。
モデム...続きを読む

Qシリアル通信の出力バッファと送信完了イベントについて

こんにちわ。よろしくお願いします。

どの言語として扱うか迷ったのですが、恐らくはC/C++が一番だろうと思ってここで質問させていただきます。

質問の内容ですが、現在、シリアル通信のアプリケーションを作っていまして、CreateFileの引数にFILE_FLAG_OVERLAPPEDを与えて非同期で読み書きを行うようにしています。
非同期ですので、OVERLAPPED構造体をstaticで宣言し、
WriteFile時に引数で与えています。
---
m_hComm = CreateFile( (const char*)pCom, GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ) ;
WriteFile(m_hComm, pwData,dwLen, &dwWrite, &osWriter);
---

問題はここからで、OVERLAPPED構造体のイベントが、シグナル状態になり、GetOverlappedResult(m_hComm, &osWriter, &dwWrite, TRUE)を抜けるのはいいのですが、実際には送信は完了しておらず、GetCommStateで通信速度を変更すると送信途中のデータが化けて通信エラーになってしまいます。

どうやら、今使用しているPCのUARTの出力バッファが大きいのか、Windows側のバッファからUARTバッファに書き込みが完了した時点でWindowsはOVERLAPPED構造体のイベントをシグナルにしているようです。
(もちろんFIFOは切ってあります)

他のPCで確認したところ、問題ありませんでした。
もしどなたか、シリアルの出力バッファを監視するいい方法があったら教えていただけないでしょうか。

こんにちわ。よろしくお願いします。

どの言語として扱うか迷ったのですが、恐らくはC/C++が一番だろうと思ってここで質問させていただきます。

質問の内容ですが、現在、シリアル通信のアプリケーションを作っていまして、CreateFileの引数にFILE_FLAG_OVERLAPPEDを与えて非同期で読み書きを行うようにしています。
非同期ですので、OVERLAPPED構造体をstaticで宣言し、
WriteFile時に引数で与えています。
---
m_hComm = CreateFile( (const char*)pCom, GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXI...続きを読む

Aベストアンサー

2400bpsで9文字の文字列を送出してからビットレートを57600bpsに変更する、という処理を5回繰り返すテストプログラムです。

ちょっと乱雑なソースですがご勘弁を。(インデントは全角スペースです。ご注意ください。)

int main(int argc, char** argv)
{
  for (int i = 0; i < 5; ++i) {
    HANDLE hFile;
    DWORD dw;

    hFile = CreateFile(
      "com1",
      GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      0,
      NULL
    );

    DCB dcb = { sizeof(DCB) };
    GetCommState(hFile, &dcb);
    dcb.BaudRate = CBR_2400;
    SetCommState(hFile, &dcb);

    char buf[100];
    sprintf(buf, "%d ABCDE\r\n", i);
    WriteFile(hFile, buf, lstrlen(buf), &dw, NULL);
    // "# ABCDE\r\n" totals 9 bytes, or 90 bits.
    // At 2400bps, 90 bits need 37.5ms to be transmitted.

#if 0
    CloseHandle(hFile);
    hFile = CreateFile(
      "com1",
      GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      0,
      NULL
    );
#endif

    Sleep(15); // 37 makes mess, 38 ok.
    dcb.BaudRate = CBR_57600;
    SetCommState(hFile, &dcb);

    Sleep(100);
    CloseHandle(hFile);
  }

  return 0;
}

同期処理にしていますが、同じ現象が発生しています。

9文字(90ビット)を2400bpsで送出すると37.5msかかる計算になるのですが、このプログラム中にあるSleep(15)の15を37にすると文字化けが発生し、38にすると文字化けが発生しないので、おおよそ計算どおりと言えるかと思います。

ここで#if 0の行を#if 1に変更すると、Sleep(15)がSleep(0)でも文字化けは発生しなくなります。つまり、デバイスのハンドルをcloseするときにはバッファがflushされるということです。

close時は必ずflushする、という記述に行き当たったわけではないので、closeさえすれば万事OKという保証はできませんが、ドライバの動作としては妥当だと思います。

#実は、「試したいこと」とはこれではなくてDevice Power Stateの変更だったのですが、そのテストをする前になんだかいい感じの結果になってしまったので(^^;

2400bpsで9文字の文字列を送出してからビットレートを57600bpsに変更する、という処理を5回繰り返すテストプログラムです。

ちょっと乱雑なソースですがご勘弁を。(インデントは全角スペースです。ご注意ください。)

int main(int argc, char** argv)
{
  for (int i = 0; i < 5; ++i) {
    HANDLE hFile;
    DWORD dw;

    hFile = CreateFile(
      "com1",
      GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      ...続きを読む

Qタイムアウトする仕組みを作りたい

VB2008でWebにアクセスしています。

アクセス時に次の関数を呼び出して、表示が完了するまで待機しています。

Private Function WebWait(ByVal time As Integer)
 Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
  Application.DoEvents()
 Loop
End Function

ただ、サイトが応答しなくてずっと待ったままになる場合があります。
10秒応答がなかった場合に処理を中断させたいのですが、方法が判りません。

PHPならば、タイムスタンプをスタート時間と比較して、終了判断させることができます。
こんな感じを考えています。

Private Function WebWait(ByVal time As Integer)
 スタート時間を格納
 Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
  Application.DoEvents()
  スタート時間と比較して、タイムアウトならLoopを抜ける
 Loop
End Function


しかし、VB2008で同様の関数を見つけることができませんでした。
dateandtimeで似たものはありますが、ずっとカウントアップするものではありませんでした。

適切な関数、もしくは方法がありましたら、教えてください。

よろしくお願いします。

VB2008でWebにアクセスしています。

アクセス時に次の関数を呼び出して、表示が完了するまで待機しています。

Private Function WebWait(ByVal time As Integer)
 Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
  Application.DoEvents()
 Loop
End Function

ただ、サイトが応答しなくてずっと待ったままになる場合があります。
10秒応答がなかった場合に処理を中断させたいのですが、方法が判りません。

PHPならば、タイムスタンプをスタート時間と比較して、終了判断...続きを読む

Aベストアンサー

タイマーコントロールを使ってはいかがですか?

タイムアウト用のフラグ変数を用意
dim m_bTimeOut as boolean

Private Function WebWait(ByVal time As Integer)
  ' タイマーの初期化
  Timer1.Enabled = false
  ' ms単位なので 10*1000 を代入
  Timer1.Interval = 10 * 1000
  ' フラグを初期化
  m_bTimeOut = false
  Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
  Application.DoEvents()
  if m_bTimeOut = true then
    Timer1.Enabled = false
    MsgBox "タイムアウトしました"
  end if
 Loop
 Timer1.Enabled = false
End Function

' タイマーイベント
Private Sub Timer1_Tick(引数省略)
  m_bTimeOut = true
  Timer1.Enabled = false
End Sub
といった具合で ・・・

タイマーコントロールを使ってはいかがですか?

タイムアウト用のフラグ変数を用意
dim m_bTimeOut as boolean

Private Function WebWait(ByVal time As Integer)
  ' タイマーの初期化
  Timer1.Enabled = false
  ' ms単位なので 10*1000 を代入
  Timer1.Interval = 10 * 1000
  ' フラグを初期化
  m_bTimeOut = false
  Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
  Application.DoEvents()
  if m_bTimeOut = true then
    Timer1.Enabled...続きを読む

QSerialPort処理でInvokeメソッドを使用するとエラーが発生。

はじめまして。こんばんわ。
同一プロジェクトの複数のフォームから、RS232C接続処理を行っております。
まったく同じ処理内容なので、クラスを使用しようとしております。
しかし、データ受信時、Invokeメソッドを使用して、各フォームのイベントをCALLしますと、『InvalidOperationException』が発生し、『ウィンドウ ハンドルが作成される前、コントロールで Invoke または BeginInvoke を呼び出せません。』というエラーメッセージが表示されてしまいます。

ソースを下記に記載いたします。どなたか、原因・対処方法がわかる方がいらっしゃいましたら、御手数をおかけいたしますが、ご教示の程、よろしくお願い申し上げます。


==============================
呼び出し元フォーム
==============================
Public Class Form1

  Private cls232CIns As cls232C

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    cls232CIns.openport()

  End Sub

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    cls232CIns = New cls232C()

  End Sub

  Public Sub DispData(ByVal data As String)

    TextBox1.Text = data

  End Sub

End Class


==============================
SerialPort通信クラス
==============================
Imports System.IO.Ports

Public Class cls232C

  WithEvents SP1 As SerialPort
  Delegate Sub RecvDataDisp(ByVal dataR As String)

  Public Sub New()

    SP1 = New SerialPort("COM6", 9600)

  End Sub

  Public Sub openport()

    SP1.Open()

  End Sub

  Public Sub closeport()

    SP1.Close()

  End Sub

  Public Sub ReceiveData(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SP1.DataReceived

    Dim getdata As String

    getdata = SP1.ReadLine
    Form1.Invoke(New RecvDataDisp(AddressOf Form1.DispData), getdata) ←ここでエラー発生

  End Sub

End Class
 

はじめまして。こんばんわ。
同一プロジェクトの複数のフォームから、RS232C接続処理を行っております。
まったく同じ処理内容なので、クラスを使用しようとしております。
しかし、データ受信時、Invokeメソッドを使用して、各フォームのイベントをCALLしますと、『InvalidOperationException』が発生し、『ウィンドウ ハンドルが作成される前、コントロールで Invoke または BeginInvoke を呼び出せません。』というエラーメッセージが表示されてしまいます。

ソースを下記に記載いたします。どなたか、原...続きを読む

Aベストアンサー

ReceiveData()では、「Form1」という暗黙のインスタンスが参照されています。
同一プロジェクトの複数のフォームから、とありますので
例えばForm1のインスタンスが無い状態でForm2上のcls232Cが機能した場合、
Form1.DispDataという関数のアドレスはForm1のインスタンスが無いので存在しないことになります。

(暗黙のインスタンスを利用して)特定のフォームを指すというクラスの設計がそもそもおかしいですよね。
「Form1」が必ず無いとcls232Cは動作しませんからね。
まずは暗黙のインスタンスを排除する必要があると思います。
例えば、Form_Loadでは
cls232CIns = New cls232C(Me)
とし、クラスでは
Private m_Form As Form
Public Sub New(oForm As Form)
SP1 = New SerialPort("COM6", 9600)
m_Form = oForm
End Sub

Invokeメソッドは
m_Form.Invoke(New RecvDataDisp(AddressOf m_Form.DispData), getdata)

とすればいいです。要は、呼び出し元のフォームを教えてあげ、Invokeするのも呼び出し元のFormに限定するわけです。
ただ、これは呼び出すフォームは必ずDispData()の実装を(訳もなく)強いられるという点など、マイナス点の多い実装です。

私ならこうします。

Imports System.IO.Ports

Public Class cls232C

Public Event Received(ByVal getdata As String)
WithEvents SP1 As SerialPort
’~略~
Public Sub ReceiveData(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SP1.DataReceived
Dim getdata As String
getdata = SP1.ReadLine
RaiseEvent Received(getdata)
End Sub
こうするとForm上のcls232CにはReceivedというイベントが出来ているはずです。

Private Sub cls232CIns_Received(ByVal getdata As String) Handles cls232CIns.Received
TextBox1.Text = getdata
End Sub

ReceiveData()では、「Form1」という暗黙のインスタンスが参照されています。
同一プロジェクトの複数のフォームから、とありますので
例えばForm1のインスタンスが無い状態でForm2上のcls232Cが機能した場合、
Form1.DispDataという関数のアドレスはForm1のインスタンスが無いので存在しないことになります。

(暗黙のインスタンスを利用して)特定のフォームを指すというクラスの設計がそもそもおかしいですよね。
「Form1」が必ず無いとcls232Cは動作しませんからね。
まずは暗黙のインスタンスを排除...続きを読む

QVB.NET(2005)の"SerialPort" RTSラインを制御

VB.NET(2005)の"SerialPort" RTSラインを制御したいです。

やりたい事は、「パソコンから通信相手の機器へデータを送信している間だけ、RTSをHIGHにする」ということです。データ送信完了と共に、RTS信号をLOWにしなくてはなりません。

SerialPortにあるRtsEnableをTrueにして、オシロで確認してみたのですが、RTS信号はHIGHに張り付いてしまっていて、全く動いていませんでした。

同じくDtrEnableをTrueにしても、同じでした。

Handshakeプロパティを"RequestToSend"に設定してみたのですが、これもまた同じ結果でした。

どなたかご存知の方がおられましたら、解決策をご教授いただければ幸いです。

Aベストアンサー

VBのRtsEnable,DtrenableはTrueにするとシリアルポートをOpenするとHiになりCloseするとLoになるだけです。
一番簡単なのは送信直前にOpenし送信完了でCloseですがちゃんとした制御をするのならAPIを使用することになります。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング