DOBON.NET DOBON.NETプログラミング掲示板過去ログ

SerialPort: 機器接続のたびに変わるCOM番号?

環境/言語:[Windows XP/7, VB.NET, .NET Framework 3.5]
分類:[.NET]

こちらには初めて投稿いたします。

USB 端子に2個の機器を接続し、COM ポートから制御するプログラムを
Visual Basic 2008 で作っています。

機器の接続状態をデバイスマネージャを見ると、接続の順序のせいなのか、
  AAA (COM1)
  BBB (COM2)
になる時と、入れ替わって
  BBB (COM1)
  AAA (COM2)
になる時があるようなのです。

機器 AAA を制御するための COM 番号を ComSerialPort.PortName に
設定するために、デバイスマネージャを目で確認するのではなく、
Visual Basic のプログラム内から行なう方法はありますか?

わかりにくい質問で恐縮ですが、ご助言をいただけましたら幸いです。
よろしくお願いいたします。
投稿者です。
補足(訂正?)します。

RS-232C の機器を RS-232C→USB 変換ケーブルで USB につないでいます。
> 機器の接続状態をデバイスマネージャを見ると、接続の順序のせいなのか、
>   AAA (COM1)
>   BBB (COM2)
> になる時と、入れ替わって
>   BBB (COM1)
>   AAA (COM2)
> になる時があるようなのです。

  PCやUSB・シリアル変換アダプタの性能に依存する場合が
  非常に高いのですが・・・

  USBポートに刺しっ放しでPCの電源投入で順番が変わると
  言う認識でよいですか?

  その場合、恐らくUSB・シリアルアダプタへの電源供給のタ
  イミングで、起動時だけ100mVを超える消費電圧になってしま
  う可能性が高く、そのような現象に陥ることはあります。

  過去エプソンPCととあるメーカーのアダプタで発生したのを
  確認しました。

  こういう使い方は適していないのですが・・・
  PCが完全に起動した後、手動で順番を守ってアダプタを挿入
  することで回避して頂きました。

  これができない・・・
  と言うのであれば、残念ながら少々高額はUSB・シリアル変
  換アダプタを使って頂く必要があります。
  要は1ポートのUSBに複数ポートを持つシリアルアダプタを
  使う。

  残るは、ノートPCのようにも思われますが、PCMCIAの
  カードスロットがあるならば、そういうものでのアダプタをお
  使いになるか、デスクトップPCの場合は、PCIバスのボー
  ドをお使いになる・・・

※ 起動後にポートチェックして相違する状態なら設定変更すると
  言うプログラムは作れないことも無いかと・・・
  ただし、VISTA以降は管理者権限が必要で、UAC設定が
  有効な場合、UACダイアログが出ますので、自動で・・・と
  なると、タスクマネージャに登録する必要があるでしょう。

以上。参考まで
シリアルポートの列挙は・・・

http://south-m.blog.so-net.ne.jp/2009-05-25-1

これなんかがよいかナ〜
英語サイトには、もっといろいろあるんだが・・・

因みにVC++です。

※ APIをっちゃんと宣言すれば、VB/C#でもOKです。

で、WMIでは本体シリアルポート以外の列挙を正しくできないので
SETUPAPIや、レジストリを検索して行う方がよいと思ってます。

※ USB・シリアル変換アダプタ作っているメーカーに言いたい!
  ちゃんとレジストリに情報を登録しろ!
  Win16のころから行儀が悪いメーカーが多い・・・

で、取得した情報から相違しているなら再設定する・・・
随分昔やったのだが、残念ながらコードが見つからなかったのだが、
多分、そのデバイスを一旦無効化してポート情報を更新し再度有効化
すればOKだったような。

レジストリのポート情報のみを更新してもダメです。その場合は再起
動が必要になるはずなんで。

以上。参考まで
オショウさん、コメントありがとうございます。

>   PCが完全に起動した後、手動で順番を守ってアダプタを挿入
>   することで回避して頂きました。

質問を投稿してからいろいろやっていくうちに、
挿入する順序や(物理的な)ポートの位置と、
COM の番号の関係がわかってきました。

オショウさんのおっしゃる「手動で順番を守って挿入」で
とりあえずは回避できそうです。


> ※ 起動後にポートチェックして相違する状態なら設定変更すると
>   言うプログラムは作れないことも無いかと・・・

このコメントを読んで思いついたのですが、
COM1 から順番に各機器に特有の ASCII コマンドを送ってみて、
コマンドに対する回答がおかしければ次の COM ポートで
同じことを繰り返す、という方法でも(力技ですが)
できそうな気がしてきました。

どうもありがとうございました。
オショウさん、追加のコメントありがとうございます。

> シリアルポートの列挙は・・・
> http://south-m.blog.so-net.ne.jp/2009-05-25-1
> これなんかがよいかナ〜
> 因みにVC++です。

VB ですら初級者なので、上記ブログを拝見しましたが、
残念ながら解読が難しそうです。。。

WMI, SETUPAPI というキーワードで少し検索してみようと思います。


かなり身勝手な理想形としては、
My.Computer.Ports.SerialPortNames
を使うと
COM1
COM2
というような COM 番号の文字列が得られますが、
これに近い形で、機器の名称である
AAA
BBB
という文字列が得られる関数があればいいなと思っています。
(それが上記ブログに書いてあるのかもしれませんが)


ありがとうございました。
> WMI, SETUPAPI というキーワードで少し検索してみようと思います。
>
> かなり身勝手な理想形としては、
>  My.Computer.Ports.SerialPortNames
> を使うと
>  COM1
>  COM2
> というような COM 番号の文字列が得られますが、
> これに近い形で、機器の名称である
>  AAA
>  BBB
> という文字列が得られる関数があればいいなと思っています。

自己レスです。
上記の理想形にかなり近いものができたので、報告します。

http://blogs.yahoo.co.jp/sirius_cma1/MYBLOG/yblog.html
のブログ記事「使用できるCOMポートを取得する」を
若干書き換えたものです。

この関数に
 FindComPortFromKey( "AAA" )
のように機器の名前(の一部)を渡すと、
 "AAA (COM1)"
という文字列が返ってきます。

あとはこの文字列から COM* の部分だけを抽出して
ポート番号として使おうと思います。

オショウさん、
キーワードをご提示いただきまして、ありがとうございました。
大変助かりました。

失礼いたします。


Public Function FindComPortFromKey(ByVal keyString As String) As String

'参考 http://blogs.yahoo.co.jp/sirius_cma1/MYBLOG/yblog.html
Dim objWMIService As Object = GetObject("winmgmts:\\.\root\cimv2")
Dim objSerialSet As Object
Dim objSerial As Object
Dim strComName As String

objSerialSet = objWMIService.ExecQuery("Select * from Win32_PNPEntity " & _
"Where (Name like '%(COM%)')")

strComName = ""
For Each objSerial In objSerialSet
If (objSerial.Name.Contains(keyString) = True) Then
If (strComName <> "") Then
strComName &= vbCrLf
End If
strComName &= objSerial.Name
End If
Next
Return strComName

End Function
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板