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

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

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

A 回答 (8件)

あんまり詳しくないですが、


全体の流れがおかしいような感じがします。

”GM”送出後”OK”を受信するまで次の処理をしてはいけないです。

大まかな流れとして。

1)GM送出
2)”OK”ポーリング&タイムアウト処理
3)”OK”正常受信時
4)”OR”送出
5)データ受信ポーリング&タイムアウト
6) 2)のタイムアウト処理
7) 6)のタイムアウト処理

Hayashi_Trekさんがおっしゃるように、よく勘違いするのが対象機の処理に非常に時間がかかる事を忘れて一気に処理をしてしまうと結果がバラバラに受信してしまう場合があります。

このような事象も前述のプロトコルアナライザーを使って通信内容を見るとコマンドの順番がおかしいことがすぐに解るんです。
    • good
    • 1

このソースでは正常動作は難しいと思います。


なぜなら
>' 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
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/05/16 11:45

説明が矛盾していますよ。



> ' GMコマンド送信後OKが戻ってきたら
ですからGMコマンドは実行されているのではないですか。

やはり状況が良く把握できません。

できる限りシンプルなプログラムを作って見せて頂けますか。
(でもやはり解決できる自信がないですけど・・・。#2,#3,#4の方いかがですか?)
    • good
    • 0

良く把握できないのでお役に立てそうもないのですが、



>' GMコマンド送信後OKが戻ってきたら
というのはこの書かれたリストでは省略されているのですよね?

「逆に実行される」とはどういうことなんでしょうか。GMコマンドは測定開始なんですよね。OKが帰ってきたと言うことは無事実行されたのではないんですか?

------
#2の方がかかれた、DoEventsは制御をOSに戻すための物です。時々OSに戻してやらないとマウスやKBやシリアルの入力を受け付けませんから。

この回答への補足

>' GMコマンド送信後OKが戻ってきたら
>というのはこの書かれたリストでは省略されているのですよね?
はい、どのように記載してよいのか分からなかったので。
試しにifで書いてみたのですが・・・だめでした。

>「逆に実行される」とはどういうことなんでしょうか。GMコマンドは測定開始な>んですよね。OKが帰ってきたと言うことは無事実行されたのではないんです ?
ハイパーターミナルのように戻り値をテキストに表示するような設定を行っているのですがORコマンド戻り値が先に表示されてしまいます。

OR,0.8
GM,OK   というような感じです。
宜しくお願い致します。

補足日時:2002/05/12 21:54
    • good
    • 0

お問い合わせの回答ではないですが、シリアル通信は電文が正確に出ているかどうかがわかりにくいので、ぜひプロトコルアナライザーを使用しましょう。


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

ビッツ
http://www.bits.co.jp/hm/hm2g.htm

ラインアイのうちLE1100
http://www.lineeye.co.jp/le1100.htm
    • good
    • 0

一応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にしたら結構良い具合になります。
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/05/12 18:03

現在のプログラムとか、計測器の通信仕様とか、もうちょい、具体的であればいいんですが・・・



1:
>なぜか、2行目が先に実行されてしまいました
1行目の分は、実行されないわけでしょうか?
もしそうなら、「輝度計」側の受信ソフトが遅くて、1行目は、「測定実行->OK」の処理中になってしまい、無視された。
あるいは、電文の区切りが違っていた。
あるいは、MSCommの設定ミス。

2:
多分、色変更が早すぎるからです。
For ループ内に DoEvents を書き加えるか、
タイマーを使ってゆっくリ色を変えるようにして、試してください。
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/05/12 17:56

お困りのようですが、情報が少なくて答えられる人は少ないと思います(特に1番)。

もう少し具体的に書いてみてはいかがでしょうか。だからといって私が答えられるとは限りません。でも他の方から回答を得られやすくなります。

2番の方ですが、これは一部分を取り出したんですよね。このままだとしたら、一瞬で0~255まで行ってしまうので白になるような気がします。

それから1番と2番は直接関係なさそうですから別々に聞かれた方が回答を得られやすいと思います。

この回答への補足

状況の説明が悪くて申し訳ありません。。。
手順としては送信コマンドをクリックしたら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に表示されるように作成しています。ぜひ、宜しくお願いします。

補足日時:2002/05/11 22:55
    • good
    • 0

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

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

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

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

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

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の場合に正常なデータと判断できます。

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...続きを読む

Qシリアル通信におけるバイトデータの送受信(VB.NET)

Visual Basic .NETで、WriteLine("テキスト")やReadLineを使えば、テキストデータは送受信できますが、バイトデータはどのようにすれば送受信できるのでしょうか?具体的なコードを知っている方がいたら教えて頂きたいです。

Aベストアンサー

こんにちは
http://msdn2.microsoft.com/ja-jp/library/ms143551(VS.80).aspx

そこまでご存知でしたらあともうひと調べでしたね。

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

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

http://msdn.microsoft.com/ja-jp/library/7ya7y41k.aspx
このサイトのコードを、参考にしています。
------------------------------------ここから
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

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

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

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

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

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

http://msdn.microsoft.com/ja-jp/library/7ya7y41k.aspx
このサイトのコードを、参考にしています。
------------------------------------ここから
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

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

Aベストアンサー

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

QC言語とシリアル通信の送受信データの概念

C言語とシリアル通信の送受信データの概念

今シリアル通信で基盤上のデータを読み書きするツールを作っています。
基盤はまだ手元にないので、先にプログラムと、基盤の動作を模したプログラムを作るつもりです。
基盤の説明にはデータはバイナリで送るようにと書かれていたので、
文字列で1バイトずつ割り当てようと考えました。
しかし、どうやって1234などの数値を1バイトずつ割り振るのか、
バイナリって何だっけと調べているうちにわけが分からなくなってきました。

たとえば1234という10進数の数値を送りたいとき、
現状ではchar型の文字列"1234"を渡しています。
もしかしてこれは間違っていて、本当は

char s[] = { 1, 2, 3, 4 };
16進数の場合はabcdなら
char s[] = { 0xa, 0xb, 0xc, 0xd };
として渡すのが正しいのでしょうか。
これでprintfを使うと文字化けして何だかバイナリっぽいぞと感じましたが。

また、バイナリ以外ならどんな送り方があるのでしょう?

Aベストアンサー

まあ、それは、データ形式の名前を気にするより、単に BCD でと言うことですね。

こんな感じで変換できますね。
(データを変換するだけなので、最初に送る 0xa1 はつけていません)

あと、BCD だと、(単純なバイナリ送信と違って) 'A' ~ 'F' に相当するコードは出てきません。
なので、0xa1 のように、「BCD としては存在しない」データがコマンドなどに割り当たっているわけです。

#include <stdio.h>

unsigned char toBCD2(int v)
{
return ( (v / 10) * 0x10 + v % 10);
}

void longToBCD(long src, char bcd[], int keta)
{
int i;
for(i = 0; i < keta; i++) // 桁は、BCD の配列の個数(安直ですが)
{
int work = src % 100;
bcd[i] = toBCD2(work);
src /= 100;
}
}

int main()
{
int i;

char result[5];
longToBCD(0x00201e90, result, 5);
for (i = 0; i < 5; i++)
{
printf("%02X ", result[i]);
}

return 0;
}

まあ、それは、データ形式の名前を気にするより、単に BCD でと言うことですね。

こんな感じで変換できますね。
(データを変換するだけなので、最初に送る 0xa1 はつけていません)

あと、BCD だと、(単純なバイナリ送信と違って) 'A' ~ 'F' に相当するコードは出てきません。
なので、0xa1 のように、「BCD としては存在しない」データがコマンドなどに割り当たっているわけです。

#include <stdio.h>

unsigned char toBCD2(int v)
{
return ( (v / 10) * 0x10 + v % 10);
}

void longToBCD(long src,...続きを読む

Qエクセル VBA でのCOMポート認識

エクセルのVBAを使用してあるアプリを作成しています。そのアプリはシリアルポートを使用してある機器と接続する事で実現できます。
そこで質問ですが、当該PCが認識しているCOMポートをVBAのSELECT BOXに表示したいのですがどうやれば(どのような関数?)を使用して実装COMポートを認識するのでしょうか?
もちろん、USB<--->シリアルケーブルを使用した場合もCOMポートだと認識しなければなりません。
よろしくお願いいたします。

Aベストアンサー

こんにちは。

Windowsのプログラム(VBA含む)から、COMポートを扱う場合は、WindowsAPI を使用すれば可能
だと思います。

COMポートの実装チェックには、WindowsAPI の「CreateFile」関数でCOMポートのオープンを実行
して、その関数の戻り値がエラーかどうかを見れば判断できると思います。
ただし、COMポートが実装されていてもエラーになるケース(既に使用中、使用不可に設定されて
いるなど)がありますので、その場合はエラーコードを取得してその値で「実装/非実装」を判断しな
いといけないと思います。

以下に、VBA から WindowsAPI (COMポート制御関連を含む)を利用するに当たって、参考になり
そうなサイトを上げてみました。宜しければ覗いてみて下さい。

■参考サイト
注)リンク切れの際は御容赦下さい。

1)VBAでWindowsAPIを使用してシリアル通信を行う方法

◎WindowsAPI講座
http://www.serpress.co.jp/winapi/
・このページよりリンクされている下記項目「シリアル通信(1)~(4)」のページでVBAから通信関連の
 APIを使用する方法が書かれています。
 NO.12 シリアル通信(1) ←必要なWindowAPI定義の説明
 NO.13 シリアル通信(2) ←シリアルポートのオープンとクローズを説明
 NO.14 シリアル通信(3) ←シリアルポートの通信プロトコル、送受信バッファ、タイムアウトの設定
 NO.15 シリアル通信(4) ←シリアルポートの送受信方法を説明
・今回の場合は、
   シリアルポートのオープン → 存在有無チェック → シリアルポートのクローズ
 までを行えば良いようなので、シリアル通信(1)~(2) までを参照すれば良いと思います。

2)CreateFile関数でCOM10以上のCOMポートを使用する際の注意点

◎CreateFile関数(Win32API)でCOM10以上を使う場合の注意点
http://www.aofactory.net/log/eid328.html
・ここで、API関数「CreateFile」で指定するCOMポート名(COM1、COM2など)に「COM10」以上を使用
 する場合の問題点および対策が書かれています。
・指定するCOMポートのデバイス名の頭に "\\.\" を付ければ良いようです。
   VBAでの指定例: "COM10" の場合は、 "\\.\COM10" とする。

3)WindowsAPI利用でCOMポートの存在有無をチェックする方法

◎COMポートが存在するかどうかを調べるには? - OKWaveの過去ログより
http://okwave.jp/qa4033242.html
・ここで、API関数「CreateFile」が失敗した際に、同じくAPI関数「GetLastError」でエラーコードを見て
 COMポートの存在有無を調べる旨が書かれています。
注)ただし、VBAでは「GetLastError」を呼んでもエラーコードが得られない可能性があるので、下記4)
 の方法を採った方が良いようです。

4)VBA から Windows API を利用する方法など

◎Office VBA と Windows API - Microsoft MSDN より
http://msdn.microsoft.com/ja-jp/library/cc326057.aspx
・このページの「エラー情報の取得」の説明で、VBAからWindowsAPIを呼出した際のエラーコードの取得
 方法が書かれています。
・VBAからWindowsAPIのDLLを呼び出した際のエラー情報は、「GetLastError関数」では取得できない
 可能性があるので、VBAの場合は「Errオブジェクト」の「LastDLLErrorプロパティ」でエラーコードを取得
 すれば良いようです。
・今回の場合は、COMポートオープン時のエラーコード取得に、この方法が利用できると思います。

こんにちは。

Windowsのプログラム(VBA含む)から、COMポートを扱う場合は、WindowsAPI を使用すれば可能
だと思います。

COMポートの実装チェックには、WindowsAPI の「CreateFile」関数でCOMポートのオープンを実行
して、その関数の戻り値がエラーかどうかを見れば判断できると思います。
ただし、COMポートが実装されていてもエラーになるケース(既に使用中、使用不可に設定されて
いるなど)がありますので、その場合はエラーコードを取得してその値で「実装/非実装」を判断しな
いといけないと...続きを読む

Qteratrermを使ったデータの送信について

teratermで
16進数で下記の5バイトを送信したいのですが、どうすればいいでしょうか。

\x85\x02\x00\x01\x86

VTウィンドウにキーボードで直接打ち込むと、一文字ごとに送信されているようで、うまく行きませんでした。

Aベストアンサー

送信したい文字列を書いたファイルを作成してください。

teratrerm メニューの「ファイル(F)」-「ファイル送信(S)」を選び、作成したファイルを選択してください。
このとき作成したファイルの内容がバイナリーの場合送信ファイル選択画面のオプションで「バイナリー(B)」にチェック入れてください。

>16進数で下記の5バイトを送信したいのですが、どうすればいいでしょうか。
たぶんバイナリーだとおもいますのでファイルはバイナリーエディターで作成してください。

注)これは日本語化したteratermでの説明です

QVisual Basic 2010を使ってRS-232Cとの通信をした

Visual Basic 2010を使ってRS-232Cとの通信をしたい。

現在、機器とPCとの通信のやりとりをするため、機器のマニュアルを見ながら悪戦苦闘しています。

通信のやり取りについては、マニュアルにVB6を使った例が書いてあります。
しかしVB6が手に入らなかったので、Visual Basic2010を現在使っています。

マニュアル(VB6向け)には
・On the Project Menu, click Components to bring up a list of additional controls available in VB6.
・Scroll through the controls and select Microsoft Comm Control 6.0. Select OK. In the toolbar at the left of the screen, the Comm Control will have appeared as a telephone icon.
・Select the Comm control and add it to the form
と書いてあります。

よく分らなかったのですが、上のメニューの「Project」⇒「Add reference」を選び、「COM」の中にあった「Microsoft Comm Control」を選びました。

が、左のツールバーには電話のアイコンは出てきませんでした。

2010の場合、VB6と違って別のやり方をしないといけないのでしょうか?


ご存知の方がいましたら、教えて頂きたいです。よろしくお願いします。

Visual Basic 2010を使ってRS-232Cとの通信をしたい。

現在、機器とPCとの通信のやりとりをするため、機器のマニュアルを見ながら悪戦苦闘しています。

通信のやり取りについては、マニュアルにVB6を使った例が書いてあります。
しかしVB6が手に入らなかったので、Visual Basic2010を現在使っています。

マニュアル(VB6向け)には
・On the Project Menu, click Components to bring up a list of additional controls available in VB6.
・Scroll through the controls and select Microsoft Comm Control 6.0...続きを読む

Aベストアンサー

SerialPortコンポーネントでシリアル通信が可能です

VB6にはMSCommというコンポーネントがあったようですが、.NET2003以降にはありません。
2005からSerialPortコンポーネントが標準でついているはずなのでそちらを使用してはいかがでしょうか?

http://msdn.microsoft.com/ja-jp/library/cc825644.aspx

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の場合、読み込んだデータがバッファに残っているということはありません。

QC#にてCTI。RS232Cの受信と送信について。

C#でCTI機能の実現を目指しております。
プログラムは以下サイトからDLして改造しています。
http://tmp.junkbox.info/e14.html
しかし、エラーが頻発し原因不明です。

構成、仕様としては、
アロハPC1という機械から電話番号データを受信しPCに受け渡し。
・データを受け取る(ここは問題なし)
データ形式は
STX(02H)、着信日時(月日曜時分9桁)、電話番号(20桁)、ETX(03H)
として送られてきます。
例) 1214112050457771111
・正常データの場合はACK(06H)を返信(これをしない場合1秒後に同データが再送される)
・データ整形
・データ表示
というような形にしたいのです。

上記サイトのプログラムをアロハPC1に合わせて通信できるようにした状態ですと、例のような生データが問題なく表示されます。
これを以下のようにしてみましたが、エラーが出てしまいます。
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// 受信文字列の取得
string receivedData = "";
string moji = "";
string moji2 = "";
try
{
receivedData = this.serialPort1.ReadExisting();
receivedData = receivedData.Replace(this.serialPort1.NewLine, "\r\n");

string[] week = { "(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)" };

string stx = receivedData.Substring(0, 1);
string etx = receivedData.Substring(30, 1);

// ACKを返す。
byte[] ack_data = new byte[1];
ack_data[0] = 06;
serialPort1.Write(ack_data,0,1);

string data_m = receivedData.Substring(1, 2);
string data_d = receivedData.Substring(3, 2);
string w = receivedData.Substring(5, 1);
int w2 = int.Parse(w);
string data_w = week[w2];
string data_h = receivedData.Substring(6, 2);
string data_i = receivedData.Substring(8, 2);

moji2 = receivedData.Substring(10, 20);
// スペースを痴漢
moji2 = moji2.Replace(" ", "");

moji = data_m + "月" + data_d + "日" + data_w + data_h + "時" + data_i + "分 ";
if (moji2 == "P")
{
moji = moji + "着信番号非通知\n";
}
else if (moji2 == "O")
{
moji = moji + "着信番号提供地域外\n";
}
else if (moji2 == "C")
{
moji = moji + "公衆電話\n";
}
else
{
moji = moji + moji2 + "\n";
}

}
catch (Exception ex)
{
moji = ex.Message;
}

// richTextBox側のスレッドに AddRecievedDataメソッドのポインタを渡して、
// 受信文字列を追加させる
AddRecievedDataDelegate add = new AddRecievedDataDelegate(AddRecievedData);
this.richTextBox1.Invoke(add, moji);
}
結果:
1221112260457771111
12月21日(月)12時26分 0457771111
1221112
startIndex に文字列の長さより大きい値を指定することはできません。
パラメータ名: startIndex260457771111
startIndex に文字列の長さより大きい値を指定することはできません。
パラメータ名: startIndex

Substringを削除すると「startIndex に文字列の長さより大きい値を指定することはできません。」というようなエラーは出てきません。
receivedData = this.serialPort1.ReadExisting();
を文字列を直接代入した場合はエラーは発生しません。

これをどのようにすれば正常に動くのでしょうか。

また、ACKが正常に送信できてないみたいなのも解れば助かります。
よろしくお願いします。

C#でCTI機能の実現を目指しております。
プログラムは以下サイトからDLして改造しています。
http://tmp.junkbox.info/e14.html
しかし、エラーが頻発し原因不明です。

構成、仕様としては、
アロハPC1という機械から電話番号データを受信しPCに受け渡し。
・データを受け取る(ここは問題なし)
データ形式は
STX(02H)、着信日時(月日曜時分9桁)、電話番号(20桁)、ETX(03H)
として送られてきます。
例) 1214112050457771111
・正常データの場合はACK(06H)を返信(これをしない場...続きを読む

Aベストアンサー

>・データを受け取る(ここは問題なし)
確認も無しに断言してはいけません。

このプログラムの問題点は、受信したデータ(receivedDat)が必ずしも31文字にならないことです。
SerialPortのDataReceived()イベントは、1文字受信するたびに発生します。
従って受信したデータには、ReadExisting()した時点でSerialPortに受信されている分しか入りません。
解決方法を2種類示しますが、動作確認はしていません。

◎解決方法1
ReadExisting()する前にBytesToReadをチェックして31文字未満ならReadしない。

◎解決方法2
一度に1文字ずつReadして文字をつないでいく。
このとき、
STXを受信する前は、Readしたデータは捨てる。(受信データは空にする)
STXを受信した後は、Readしたデータを受信データに継ぎ足していく。
ETXを受信したら(継ぎ足したデータがETXなら)、受信データ長を確認してACK送信にすすむ。


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

人気Q&Aランキング