VB.net(VB2022)のSerialPortの実装とイベントの追加方法

組み込みエンジニア
本記事はプロモーションが含まれています。

こんにちは、ENGかぴです。

Visual Basic 2022はMicroSoft社がVisual Studioで提供している開発環境です。Visual Basic2022のデスクトップアプリでシリアルポートの実装とイベントの追加方法をまとめました。

シリアルポート(SerialPort)を実装し、Arduino UNOとシリアル通信を行い動作確認を行います。

Visual Studio Community 2022は基本無料で使用できるため個人の趣味でアプリを作ってみたい方やプログラミングの学習にお勧めの開発環境です。Visual Studio Community 2022のインストール方法については下記記事にまとめています。

Visual Studio 2022によるVBの開発環境の作り方

Visual Basic 2022を以下ではVB2022とします。

SerialPortを実装する

スタートメニューからVisual Studio 2022を起動し、VB2022のプロジェクトを作成します。初期配置されているフォームにボタンを実装しイベントを追加します。

毎回スタートメニューから開くのが面倒な場合はタスクバーにピン止めもしくはスタートメニューのVisual Studio 2022を左クリックで選択した状態でデスクトップにリンクコピーしても良いと思います。

広告

SerialPortを使って作成するアプリ

本記事で作成するアプリの動作画面
本記事で作成するアプリの動作画面

本記事ではシリアル通信のCOMポートを選択して外部機器と通信をするアプリを作成します。

テキストボックスにデータを入力し「送信」を押すと外部機器に入力したデータを送信します。外部機器からの受信した文字列を下のテキストボックスに表示します。

作成したアプリと外部機器(Adruino UNO)をUSB接続でシリアル通信を行います。

プロジェクトの作成

プロジェクトの作り方は下記記事のVisual Studio(VB2022)のプロジェクトを作成する   を参考にしてください。

Visual Studio 2022によるVBの開発環境の作り方

本記事ではプロジェクト名とソリューション名を「SerialTest」にしています。

スポンサーリンク

SerialPortの追加

初期で配置されているForm1.vb[デザイン]にSerialPortを追加します。ツールボックスのコンポーネントからSerialPortを選択します。(すべてのWindows Formsからも選択できます。)Form1を任意の名称に変更している場合はForm1を変更した名前に置き換えて下さい。

SerialPortの追加
SerialPortの追加

SerialPortを選択した状態でフォーム内を左クリック、またはSerialPortを選択してダブルクリックするとSerialPortが追加されます。SerialPortはSerialPort1のように追加した順に番号が付加されます。

SerialPort1を選択するとプロパティが表示されます。ソースコードでCOMポートや通信条件は可変する場合はプロパティで変更する必要はありません。私が良く使用しているプロパティについてまとめました。

項目説明
PortName通信ポートを指定します。
例)COM1、COM10
BaudRate通信のボーレートを指定します。
例)115200、9600、19200
Databitsデータのビット数を指定します。(最近は8ビットのものが多い)
例)7、8
Parityパリティーチェックの使用方法を指定します。
例)None、Odd、Even、Mark、Space
StopBitsストップビットを指定します。
例)One、Two、OnePointFive
Handshakeデータ交換のフロー制御のハンドシェークを指定します。
例)None、XOnXOff、RequestTosend、RequestToSendXOnXOff
ReadBufferSize読み取りバッファーのサイズを指定します。
このサイズを超える前にRead()でデータを読み込む必要があります。
WriteBufferSize送信するデータを一時保管するサイズを指定します。
このサイズを超えて送信する場合は分割する必要があります。
使用するプロパティの項目

通信相手となる外部機器の通信仕様を確認するのが一番ですが、最近ではPortNameとボーレート以外のプロパティは変更せずデフォルト値で動作することが多い印象です。

USBのドライバーICのハード構成によりますが、RtsEnabledまたはDtrEnableのいずれかをTrueにしないと通信できないことがあります。Seeeduino XAIOの場合は上記の通りで、Arduino UNOの場合はどちらもFalseでも通信することができます。

基本的にRtsEnabled及びDtrEnableはデフォルトの通りFalseで指定し、通信できなければ必要に応じてTrueを指定する確認方法でよいと思います。

広告

コントロールの実装

SerialPortの動作確認を行うため各種コントロールをFormに追加します。コントロールの実装とイベントの追加の方法を下記記事にまとめています。

VB.net(VB2022)のボタンの実装とイベントの追加方法

Formにツールボックスからコントロールを追加し、一部のプロパティを変更します。

コントロールの追加
コントロールの追加

GroupBox1の中にComboBox1、ComboBox2、Button1、Button2を配置します。GroupBox1のTextプロパティを「シリアル通信」に変更します。

ComboBox1はSerialPort1のPortName(COMポート)の指定に使用します。ComboBox2はシリアル通信のBaudRate(ボーレート)の指定に使用します。どちらもソースコードで選択肢を追加します。

Button1はCOMポートの再検索に使用します。Textプロパティを「再検索」に変更します。BackColorプロパティをWebタブからLightGreenに変更します。

Button2はCOMポートの設定(PortName、ボーレート、その他)の条件でポートを開きます。Textプロパティを「オープン」に変更します。BackColorプロパティをWebタブからLightGreenに変更します。

Button3はTextbox1に入力した文字の送信に使用します。Textプロパティを「送信」に変更します。BackColorプロパティをWebタブからLightGreenに変更します。

Button4はTextbox2のクリアに使用します。Textプロパティを「テキストクリア」に変更します。BackColorプロパティをWebタブからLightGreenに変更します。

Textbox1は送信する文字列を入力します。デバッグで文字を入力するのは手間なのでTextプロパティを「Serial Test 1234」に変更します。この文字列はデバッグで任意の文字に変更できます。

Textbox2は外部機器から受信した文字列を表示します。MultiLineプロパティにTrueを指定します。ReadOnlyプロパティをTrueを指定して文字を書き込めないようにします。ReadOnlyプロパティをTrueにするとデフォルトでBackColorがControl色になるためBackColorプロパティをWebタブからWhiteに変更します。

広告

変数の宣言

アプリで共通する変数を宣言する場合はフォームクラス内で変数を宣言する必要があります。VBの場合はDimでメモリに変数を割り当てます。

Public Class Form1

    Structure TYP_COMRING
        Dim rp As Integer
        Dim wp As Integer
        Dim dat() As Byte
    End Structure

    Dim RxRing As TYP_COMRING’受信したデータを管理
End Class

例ではアプリ全体で使用できるTYP_COMRINGの型の変数をRxRingで宣言しています。クラス内で宣言した場合はアプリを終了しない限りメモリを割り当てた状態になります。

RxRingはSerialPort1で受信したデータを格納するために使用します。wpで格納場所を更新しながら受信したデータを格納します。rpは受信したデータを表示したときに更新します。

wpとrpの差で受信したデータの有無を確認しTextbox2に文字列として表示します。

イベントの追加

Button1などのコントロールに対してイベントの追加を行う必要があります。エディターを選択している状態でF7を押すか、右クリックで表示されるメニュー「コードの表示(C)」を選択するとコードの編集画面(Form1.vb)に遷移します。次のイベントを追加します。

  1. フォームを呼び出したときに一度だけ処理するLoadイベント
  2. SerialPort1がデータを受信したときに呼び出すDataReceivedイベント
  3. Timer1がインターバルの間隔で呼び出された時に処理するTickイベント
  4. Button1をクリックしたときに呼び出すClickイベント
  5. Button2をクリックしたときに呼び出すClickイベント
  6. Button3をクリックしたときに呼び出すClickイベント
  7. Button4をクリックしたときに呼び出すClickイベント

1~6のイベントは、クリックとダブルクリックで追加することができます。フォームのLoadイベントはForm1[デザイン]をダブルクリックすると追加されます。ButtonのClickイベントはButton1~Button4をダブルクリックするとがイベントが追加されます。

Loadイベント、Clickイベント以外を追加する場合もあるため、以下ではコードエディターでSerialPort1のDataReceivedイベントを追加する方法を説明します。

SerialPortのDataReceivedイベントを追加する方法
SerialPortのDataReceivedイベントを追加する方法

コントロール選択でSerialPort1を選択します。コントロール選択の横にあるイベント一覧からDataReceivedを選択するとイベントが追加できます。イベントを選択すると自動でイベントのハンドラが生成されます。

Private Sub SerialPort1_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    '処理を追加
End Sub

自動生成されたサブルーチンの後方にHandles SerialPort1.DataReceivedのように記述されている部分がイベントの発生要因になります。

PR:テックジム:プログラミングの「書けるが先で、理解が後」を体験しよう!

イベントに処理を追加する

イベントが発生した時の処理を追加します。イベントの追加で作成したサブルーチンに処理を追加します。処理の内容は以下の通りです。

  • フォームを読み込んだ時に初期化を行う。
  • SerialPort1が受信したデータを格納する。
  • Timer1のインターバル毎に受信したデータがあればTextbox2に表示する。
  • Button1をクリックするとポートの再検索を行う。
  • Button2をクリックするとポートをオープンする。
  • Button3をクリックするとTextbox1の文字列を送信する。
  • Button4をクリックするとTextbox2の文字列をクリアする。

フォームを読み込んだ時に初期化

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ComboInit() 'Comboboxを初期化する
    RxRingInit() 'RxRingの初期化を行う 
End Sub

Form1_Load()関数はForm1が読み込まれた時に一度だけイベントが発生します。自作の関数でComboBoxの初期化、RxRingの初期化を行います。

'Comboboxを初期化する
Private Sub ComboInit()
    ComPortChk() 'ComboBox1の初期化(ポートの検索)
    ComboBox2.Items.Add("9600")
    ComboBox2.Items.Add("19200")
    ComboBox2.Items.Add("115200")
    ComboBox2.Text = "115200"
End Sub

ComboInit()関数はComboBoxの初期化を行います。ComboBox1の初期化はComPortChk()関数で行います。

ComboBox2はItemsプロパティのAdd()メソッドで選択肢を追加しています。初期の表示のためTextプロパティに115200を指定しています。

'存在するポートを検索する
Private Sub ComPortChk()
    Dim comno() As String = SerialPort.GetPortNames
    Dim i As Integer

    ComboBox1.Items.Clear() 'アイテムをクリア

    If comno.Length = 0 Then
        ComboBox1.Text = "COMポートがみつかりません。"
    Else
        For i = 0 To comno.Length - 1
            ComboBox1.Items.Add(comno(i))
        Next
        ComboBox1.Text = comno(0)
    End If
End Sub

SerialPortクラスのGetPortNames()メソッドで存在するCOMポートの番号を取得します。複数存在することがあるためcomno[]配列で格納しています。取得したCOMポートをComboBox1に追加します。追加を繰り返すと同じCOMポートが追加されてしまうため、ItemsプロパティをClear()メソッドでクリアします。

COMポートが存在する場合はComboBox1のItemsプロパティのAdd()メソッドで追加します。ComboBox1の初期表示のためTextプロパティに配列の0番目の文字列を指定しています。

SerialPort1が受信したデータを格納

Private Sub SerialPort1_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    Dim sz As Integer = SerialPort1.BytesToRead
    Dim i As Integer
    Dim rxdat(sz - 1) As Byte

    SerialPort1.Read(rxdat, 0, sz)

    For i = 0 To sz - 1
        RxRingSet(rxdat(i))
    Next
End Sub

SerialPortクラスのBytesToRead()メソッドで受信したバイト数をSerialPort1の受信バッファから取得します。rxdat()はSerialPort1に保管されているデータを一時格納するために使用します。

SerialPortクラスのRead()メソッドでSerialPort1に保管されているデータを読み込みます。第1引数にデータの格納先のアドレスを指定します。第2引数にデータの読み込みのオフセットを指定します。第3引数にデータ数を指定します。次に一時保管したrxdat()のデータをRxRingに格納します。

'RxRingのwpを更新する
Public Sub RxRingSet(ByVal dat As Byte)
    RxRing.dat(RxRing.wp) = dat
    RxRing.wp += 1

    If RxRing.wp = RxRing.dat.Length Then
        RxRing.wp = 0
    End If
End Sub

RxRingSet()関数はSerialPort1から取得したデータをRxRingのwpを更新しながら格納する自作の関数です。

引数に格納するデータを指定します。RxRing.dat[]にデータを格納するとwpを更新します。wpの更新がRxRing.dat[]の総数を超えると0に戻します。

広告

Timer1のインターバル処理

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Dim sz As Integer
    Dim i As Integer

    sz = RxRing.wp - RxRing.rp

    If sz < 0 Then
        sz += RxRing.dat.Length
    End If

    If sz > 0 Then
        For i = 0 To sz - 1
            TextBox2.Text &= Chr(RxRing.dat(RxRing.rp))
            RingRpAdd()
        Next
    End If
End Sub

Timer1のEnabledをTrueにするとインターバル毎にTimer_Tick()のイベントが発生します。インターバル毎に受信データのサイズをwpとrpの差を計算して確認します。サイズが0未満の場合はwpがRxRing.dat[]の総数を超えて0に戻ったことになるためRxRing.dat[]の総数を加えてサイズとします。

サイズが0より大きい場合はTextBox2のTextプロパティに文字を追加します。RxRing.dat[]のデータをChr()メソッドで文字コードに対応する文字に置き換えて追加します。

文字を追加すると同時にRingRpAdd()関数でRxRing.rpを更新して受信データを処理したと判断します。

'RxRingのrpを更新する
Private Sub RingRpAdd()

    RxRing.rp += 1
    If RxRing.rp >= RxRing.dat.Length Then
        RxRing.rp = 0
    End If

End Sub

RingRpAdd()関数はRxRingのrpを更新する自作の関数です。rpはデータの読み込みが完了した場合に更新します。

RxRing.rpを+1してrpを更新します。rpの更新がRxRing.dat[]の総数を超えると0に戻します。

Button1をクリック

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ComPortChk() '存在するポートを検索する
End Sub

Button1をクリックするとButton1_Click()のイベントが発生します。Button1はCOMポートを再検索する処理を追加します。処理はフォームを読み込んだ時に初期化で使用しているComPortChk()関数で行います。

スポンサーリンク

Button2をクリック

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    PortOpen() 'ポートをオープンする
End Sub

'ポートをオープンする
Private Sub PortOpen()
    Try
        With SerialPort1
           .Close() 'ポートを閉じる
           .PortName = ComboBox1.Text
           .BaudRate = ComboBox2.Text
           .DataBits = 8
           .Parity = Parity.None
           .StopBits = StopBits.One
           .Handshake = Handshake.None
           .RtsEnable = False
           .DtrEnable = False
           .Open() 'ポートをオープンする
        End With

        Timer1.Enabled = True
    Catch ex As Exception
        MsgBox(ComboBox1.Text & "をオープンできませんでした。", MsgBoxStyle.OkOnly)
    End Try
End Sub

Button1をクリックするとButton2_Click()のイベントが発生します。COMポートをオープンする処理を追加します。処理は自作のPortOpen()関数で行います。

COMポートのオープンに失敗した場合にアプリが強制終了しないようにTry Catch文で処理を行います。Tryの部分に処理する内容を追加します。Catchの部分には失敗したときの処理を追加します。

SerialPort1の設定を指定します。Close()メソッドで現在のCOMポートをクリアします。PortNameとBaudRateの設定はComboBox1、ComboBox2で選択した値を使用します。残りの項目は通信相手に合わせた固定の値を指定します。Open()メソッドでCOMポートをオープンします。

With イベント名 ~ End Withの間はイベント名を省略することができます。例).PortNameはSerialPort1.PortNameと同じです。

PR: 未経験OK、20代の理系に特化した就職、転職サービス UZUZ(ウズウズ)

Button3をクリック

Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click

    If SerialPort1.IsOpen Then
        SerialPort1.Write(TextBox1.Text)
    End If
End Sub

Button3をクリックするとButton3_Click()のイベントが発生します。TextBox1のTextプロパティに指定されている(テキストに入力した文字列)を送信する処理を追加します。

COMポートがオープンしていない状態で送信しようとするとアプリが強制終了してしまうので、COMポートの状態をIsOpenメソッドで確認します。COMポートがオープンしている場合はWrite()メソッドの引数に文字列を指定してデータを送信します。

Button4をクリック

Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
    TextBox2.Clear()
End Sub

Button4をクリックするとButton4_Click()のイベントが発生します。TextBox2のTextプロパティに指定されている(テキストに入力した文字列)をクリアする処理を追加します。

Clear()メソッドでTextBoxのTextプロパティをクリアします。

広告

ポート検索でデバイス名を表示する方法

COMポートを検索するとCOM1やCOM7とCOM番号が表示されます。COM番号のみの表示の場合、複数ポートが存在する場合に対象の機器がどれかが分かりにくいことがあります。デバイス名を表示して対象の機器を判別しやすくする方法をまとめました。

デバイス名を取得するためにレジスタを参照する必要があります。WMI(Windows Management Instrumentation)を使用してレジスタの情報を取得するためSystem.Management.dllを追加します。

My Projectのプロパティを開いて参照設定を表示
My Projectのプロパティを開いて参照設定を表示

ソリューションエクスプローラー内のMy projectを選択して参照設定を開きます。ダブルクリックするか右クリックから「開く」を選択すると参照設定が表示されます。「追加(A)」をクリックします。

System.Managementを追加
System.Managementを追加

アセンブリからSystem.Managementを一覧から選択しチェックを入れて「OK」をクリックするとプロジェクトSystem.Managementがインポートされて使用することができます。

System.Managementで使用するWin32_SerialPortクラスについては下記リンクに詳細があります。

Win32_SerialPort クラス – Win32 apps | Microsoft Learn

Win32_SerialPortクラスからデバイス名を表示するためNameプロパティを使用します。WMIから取得したデバイス名を表示する例は以下の通りです。

'存在するポートを検索する
Private Sub ComPortChk2()
    Dim mngstr As New Management.ManagementObjectSearcher("Select * from Win32_SerialPort")
    Dim mc As Management.ManagementObjectCollection
    Dim serial As Management.ManagementBaseObject
    Dim comno() As String = SerialPort.GetPortNames
    Dim i, j As Integer
    Dim serialcnt As Integer
    Dim comcnt As Integer
    Dim strno As Byte
    Dim str As String
    Dim comstr As String

    mc = mngstr.Get()'Searcherの結果を取得
    serialcnt = mc.Count
    comcnt = comno.Length
    ReDim ComInfo(serialcnt - 1)

    For Each serial In mc
        ComInfo(i).dvicename = serial("Name")
        strno = InStr(ComInfo(i).dvicename, "(COM")
        If strno <> 0 Then
            strno += 1
            comstr = ""
            For j = 0 To 6
                str = Mid(ComInfo(i).dvicename, strno + j, 1)
                If str <> ")" Then
                    comstr &= str
                Else
                    Exit For
                End If
            Next
            ComInfo(i).comno = comstr
        End If

        i += 1
    Next

    ComboBox1.Items.Clear() 'アイテムをクリア

    If serialcnt = 0 Then
        ComboBox1.Text = "COMポートがみつかりません。"
    Else
        For i = 0 To ComInfo.Length - 1
            ComboBox1.Items.Add(ComInfo(i).dvicename)
        Next
        ComboBox1.Text = ComInfo(0).dvicename
    End If
End Sub

System.Management(NameSpace名)内で定義されているクラスを使用します。デバイス名を取得するためにManagementObjectSearcher()クラスの変数としてmngstrをインスタンス化します。引数は管理情報に対するクエリを指定します。

例はシリアル通信ポートの情報が格納しているWin32_SerialPortクラスからすべての情報を取得する命令(クエリ)を指定しています。

SQLので対象のデータベースからすべてのデータを取得するクエリは以下の通りです。「SELECT * FROM 対象のデータベース

ManagementObjectSearcher()で取得した結果をGet()メソッドで取得し、ManagementObjectCollectionクラスの変数のmcに格納します。

For Each分は指定した要素の分だけ繰り返すループです。ManagementBaseObjectクラスの変数のserialが要素になりますが、INによってmcの情報が引き継がれた状態でループします。

ManagementBaseObjectクラスは引数でプロパティ指定することができます。Win32_SerialPortクラスのプロパティからNameを指定して取得した結果をComInfo[].dvicenameに格納します。

取得したデバイス名にCOMXXとCOM番号が入っていますが、デバイス名を含めた状態ではCOMポートのオープンに使用できないためCOM番号のみを指定できるようにデバイス名からCOMXXの部分だけを抜き取ったデータを準備する必要があります。

InStr()メソッドで「(COM」が含まれていることを確認し、Cの位置から「)」までの文字列を連結してCOMXXのデータを生成しComInfo[].comnoに格納しています。

ComboBox1の表示にComInfo[].dvicenameを使用しCOMポートのオープンにComInfo[].comnoを使用することでデバイス名で選択したCOMポートをオープンすることができます。

スポンサーリンク

動作確認(デバッグ)

デバッグ開始の方法
デバッグ開始の方法

イベントの処理を追加した後は動作確認(デバッグ)を行います。デバッグは実際のアプリケーションの動作を模擬して実行するものです。デバッグの開始はエディタ上部の「▶開始」(赤枠)をクリックすると開始します。

動作確認の結果
動作確認の結果

Arduino UNOをUSB接続して待機させます。デバッグの開始でアプリをスタートし、接続先をArduino Uno(COM10)を選択します。COM10は使用する環境によって番号が異なることがあります。ボーレートをArduino UNOと揃えて115200を選択します。

オープンをクリックするとCOMポートがオープンします。Textbox1にArduino UNOに送信する文字を入力します。(入力するのが面倒なのでTextプロパティにSerial Test 1234を指定しています。)

「送信」をクリックするとArduino UNOに文字列を送信します。Arduino UNOからの返信は下のテキストボックスに表示されます。動作確認の結果では複数回送信を押した結果が表示されています。「テキストクリア」をクリックすると受信した文字列をクリアできます。

Arduino UNOのUSBを抜いて再検索するとCOMポートが消えていることも確認できました。また、再度接続し「再検索」をクリックするとArduino UNOのCOMポートが表示されることも確認できました。

VB.netでシリアル通信を使用することでArduino UNOなどシリアル通信ができるマイコンに対して任意の電文を送信するデバッグができるようになります。

コードのデバッグを行う場合は、コードエディタでブレークポイントを置くことで一時的にプログラムを停止させることができます。

ブレークポイントでデバッグする方法
ブレークポイントでデバッグする方法

ブレークポイントはコードエディターの最左部分をクリックして●マークが表示されれば設置できています。例ではButton3がクリックされた時に発生したイベントの先頭部分にブレークポイントを置いています。この状態でButton3をクリックするとブレークポイントでプログラムが一時停止します。

F11を押すとステップ実行になるため1行ずつ内容を確認しながらデバッグを行うことができます。上部の「▶続行(C)」をクリックするとブレークポイント状態から通常の動作に復帰します。

広告

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

Imports System.IO.Ports

Public Class Form1

#Const MNI_ENABLE = 1'1:WMI有 0:WMI無し 

    Const RXRGSZ As Integer = 64

    Structure TYP_COMRING
        Dim rp As Integer
        Dim wp As Integer
        Dim dat() As Byte
    End Structure

    Structure COM_PORT
        Dim dvicename As String
        Dim comno As String
    End Structure

    Dim RxRing As TYP_COMRING '受信したデータを管理
    Dim ComInfo() As COM_PORT
    Dim selectComNo As Integer

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ComboInit() 'Comboboxを初期化する
        RxRingInit() 'RxRingの初期化を行う
    End Sub

    'RxRingの初期化を行う
    Private Sub RxRingInit()
        RxRing.wp = 0
        RxRing.rp = 0
        ReDim RxRing.dat(RXRGSZ - 1)
    End Sub

    'Comboboxを初期化する
    Private Sub ComboInit()

#If MNI_ENABLE Then
        ComPortChk2() 
#Else
        ComPortChk() 'ComboBox1の初期化(ポートの検索)
#End If
        ComboBox2.Items.Add("9600")
        ComboBox2.Items.Add("19200")
        ComboBox2.Items.Add("115200")
        ComboBox2.Text = "115200"
    End Sub

    '存在するポートを検索する
    Private Sub ComPortChk()
        Dim comno() As String = SerialPort.GetPortNames
        Dim i As Integer

        ComboBox1.Items.Clear() 'アイテムをクリア

        If comno.Length = 0 Then
            ComboBox1.Text = "COMポートがみつかりません。"
        Else
            For i = 0 To comno.Length - 1
                ComboBox1.Items.Add(comno(i))
            Next
            ComboBox1.Text = comno(0)
        End If

    End Sub

    '存在するポートを検索する
    Private Sub ComPortChk2()
        Dim mngstr As New Management.ManagementObjectSearcher("Select * from Win32_SerialPort")
        Dim mc As Management.ManagementObjectCollection
        Dim serial As Management.ManagementBaseObject
        Dim comno() As String = SerialPort.GetPortNames
        Dim i, j As Integer
        Dim serialcnt As Integer
        Dim comcnt As Integer
        Dim strno As Byte
        Dim str As String
        Dim comstr As String

        mc = mngstr.Get()
        serialcnt = mc.Count
        comcnt = comno.Length
        ReDim ComInfo(serialcnt - 1)

        For Each serial In mc
            ComInfo(i).dvicename = serial("Name")

            strno = InStr(ComInfo(i).dvicename, "(COM")
            If strno <> 0 Then
                strno += 1
                comstr = ""
                For j = 0 To 6
                    str = Mid(ComInfo(i).dvicename, strno + j, 1)
                    If str <> ")" Then
                        comstr &= str
                    Else
                        Exit For
                    End If
                Next
                ComInfo(i).comno = comstr
            End If

            i += 1
        Next

        ComboBox1.Items.Clear() 'アイテムをクリア

        If serialcnt = 0 Then
            ComboBox1.Text = "COMポートがみつかりません。"
        Else
            For i = 0 To ComInfo.Length - 1
                ComboBox1.Items.Add(ComInfo(i).dvicename)
            Next
            ComboBox1.Text = ComInfo(0).dvicename
        End If

    End Sub

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

#If MNI_ENABLE Then
        ComPortChk2() '存在するポートを検索する
#Else
        ComPortChk() '存在するポートを検索する
#End If

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        PortOpen() 'ポートをオープンする
    End Sub

    'ポートをオープンする
    Private Sub PortOpen()

        Try
            With SerialPort1
                .Close() 'ポートを閉じる

#If MNI_ENABLE Then
                .PortName = ComInfo(selectComNo).comno
#Else
                .PortName = ComboBox1.Text
#End If
                .BaudRate = ComboBox2.Text
                .DataBits = 8
                .Parity = Parity.None
                .StopBits = StopBits.One
                .Handshake = Handshake.None
                .RtsEnable = False
                .DtrEnable = False
                .Open() 'ポートをオープンする
            End With

            Timer1.Enabled = True
        Catch ex As Exception
            MsgBox(ComboBox1.Text & "をオープンできませんでした。", MsgBoxStyle.OkOnly)
        End Try
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        SerialWrite()
    End Sub

    Private Sub SerialWrite()

        If SerialPort1.IsOpen Then
            SerialPort1.Write(TextBox1.Text)
        End If

    End Sub

    Private Sub SerialPort1_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        Dim sz As Integer = SerialPort1.BytesToRead
        Dim i As Integer
        Dim rxdat(sz - 1) As Byte

        SerialPort1.Read(rxdat, 0, sz)

        For i = 0 To sz - 1
            RxRingSet(rxdat(i))
        Next

    End Sub

    'RxRingのwpを更新する
    Public Sub RxRingSet(ByVal dat)

        RxRing.dat(RxRing.wp) = dat

        RxRing.wp += 1
        If RxRing.wp = RxRing.dat.Length Then
            RxRing.wp = 0
        End If
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim sz As Integer
        Dim i As Integer

        sz = RxRing.wp - RxRing.rp

        If sz < 0 Then
            sz += RxRing.dat.Length
        End If

        If sz > 0 Then
            For i = 0 To sz - 1
                TextBox2.Text &= Chr(RxRing.dat(RxRing.rp))
                RingRpAdd()
            Next

        End If

    End Sub

    'RxRingのrpを更新する
    Private Sub RingRpAdd()

        RxRing.rp += 1
        If RxRing.rp >= RxRing.dat.Length Then
            RxRing.rp = 0
        End If

    End Sub

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        TextBox2.Clear()
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
        selectComNo = ComboBox1.SelectedIndex
    End Sub
End Class

MNI_ENABLEの値を0から0以外に切り替えることでデバイス名の表示を切り替えることができます。

コントロールの番号やイベントハンドラーなどのプロパティ名などを変更している場合はソースコードのイベントハンドラーをお使いのイベントハンドラーに置き換えて使用してください。

本記事ではポートの設定をポート番号とボーレートのみに限定しましたが、他の項目についてもComboBoxで変更できるようにしても良いと思います。

動作確認のため使用したArduinoのソースコードは以下の通りです。

void setup() {
  Serial.begin(115200);
}

void loop() {
  
  while(Serial.available()){
    Serial.write(Serial.read());
  }
}

受信した文字列をそのまま返信するソースコードです。

関連リンク

VBでインストール先を指定できるインストーラを作成する方法を下記記事にまとめています。

VBでインストール先を指定するインストーラを作成する方法

マイクロソフトはVisual Studio以外にもVSCodeという便利なエディターを提供しています。下記リンクではVSCodeのインストールの仕方からC言語開発環境の作り方までをまとめています。

VSCodeをインストールしてC/C++の開発環境を作る

PR:技術系の通信教育講座ならJTEX

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました