[2018/11/27] SerialPortコントロールの使い方その5(データ受信時及び、信号変化時にイベントを発生させる) (No.71)
[2018/10/31] SerialPortコントロールの使い方その4(データ受信時にイベントを発生させる) (No.64)
[2018/10/30] SerialPortコントロールの使い方その3(外部装置からの垂れ流しデータ受信) (No.63)
[2018/10/01] テキストボックス拡張クラスにプロパティを追加する方法 (No.57)
[2018/06/06] SerialPortコントロールの使い方その2 (No.49)
-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
前回のSerialPortコントロールを使い方その4では、データ受信時にイベントを発生させる様にしましたが、 今回は通信の制御信号の変化を捉えられる様にイベントを追加しました。
シリアル通信の接続にはDサブコネクタが用いられますが、昔はRS232Cと呼ばれていた規格がありまして パソコン同士では以下の様な接続が一般的でした。ピンの番号はDサブ25ピンを元にしていますので、 いわゆるPC-AT互換機のDサブ9ピンで考える場合は、信号名で合わせて下さい。 (私自身は昔の人間ですので、Dサブ25ピンが普通でした)
パソコン同士の接続を示しますが、外部機器との接続も大体これで問題無いと思います。
データ線の TXD と RXD をテレコにして、 RTS と CTS DSR と DTR も同様にテレコに接続します。
こちら側の送信データは相手側の受信データですし、相手側の送信データはこちら側の受信データになるという考えです。 制御信号の線も同様となります。
制御信号を見ないのであれば、究極以下の接続でも可能です。制御信号をそれぞれのコネクタの中でループバックして接続します。 FG と GND は必ず接続しますが、FG は無くても動作します。FG はケーブルの被服のシールドの部分を接続するのですが、 雑音対策としては推奨します。
今まで各種機器の接続を行ったことがありますが、意外とこの方法が多かったりします。 外部機器側でも制御信号をコントロールするプログラムを組むのも面倒なのかと思います。(実際、装置側のプログラムは面倒です)
制御信号を見なくても機器側ではデータを送信する為に、先ずパソコン側から送信要求コマンドを送ってから 機器側でコマンドに従ってデータを送信する場合が一般的です。 パソコン側からコマンドを送ってデータが送信されてこない場合、タイムアウトで機器が接続されていないか、 または機器が何かの原因で反応しないかが分かります。
それでは、「その4」のシリアル通信クラスに制御信号の変化イベントを追加します。 イベントアーギュメントの元クラスの EventArgs を継承し SerialCTSChangeEventArgs と SerialDSRChangeEventArgs を宣言します。 追加するプロパティとして各信号の値を宣言します。
制御信号イベント・通知アーギュメント用クラス
Public Class SerialCTSChangeEventArgs Inherits EventArgs Private mblnCTS As Boolean ' 制御信号データを取得 Public Property CTS() As Boolean Get Return mblnCTS End Get Set(ByVal value As Boolean) mblnCTS = value End Set End Property End Class Public Class SerialDSRChangeEventArgs Inherits EventArgs Private mblnDSR As Boolean ' 制御信号受信データを取得 Public Property DSR() As Boolean Get Return mblnDSR End Get Set(ByVal value As Boolean) mblnDSR = value End Set End Property End Class
この通知アーギュメントクラスを利用して、「その4」のシリアル通信クラスを変更します。 変更内容は以下の通りです。- Event を使ってイベントを定義を行う。
- 制御信号アーギュメントクラスを生成し、制御信号データをその中に設定する。
- 制御信号の変化時に、RaiseEvent を使って各CTS、DSR信号イベントを発生する。
SerialPortコントロールの使い方その5(通信用クラス)
Imports System.IO.Ports ''' ----------------------------------------------------------------------- '''
''' シリアル通信クラス・垂れ流し受信イベント付き2 ''' ''' ----------------------------------------------------------------------- Public Class ClsSerialRcvEvent2 '''''' シリアルポートクラス ''' '''Private SerialPort As SerialPort ''' ''' 読込データ格納先 ''' '''データ受信イベントで蓄えられる Private CmdBuf() As Byte '''''' STX受信フラグ(装置の送信が開始された証拠) ''' Private fSTX As Boolean = False '''''' 最終受信文字列(受信データからSTX,ETXを除いたもの) ''' '''Private strLastRxData As String = "" ''' ''' 送受信文字列の開始コード(STX:0x02) ''' Private Const CMD_STX As Byte = &H2 '''''' 送受信文字列の終了コード(ETX:0x03) ''' Private Const CMD_ETX As Byte = &H3 '''''' データ受信イベント定義 ''' Public Event ReceivedData(ByVal sender As Object, ByVal e As SerialEventArgs) '''''' CTS受信イベント定義 ''' Public Event CTSChanged(ByVal sender As Object, ByVal e As SerialCTSChangeEventArgs) '''''' DSR受信イベント定義 ''' Public Event DSRChanged(ByVal sender As Object, ByVal e As SerialDSRChangeEventArgs) ''' ----------------------------------------------------------------------- '''''' コンストラクタ ''' ''' <param name="SerialPort">シリアルポートコントロール</param> ''' ----------------------------------------------------------------------- Sub New(ByVal SerialPort As SerialPort) 'シリアルポートの退避 Me.SerialPort = SerialPort '受信イベントのハンドラ設定 AddHandler Me.SerialPort.DataReceived, AddressOf DataReceivedHandler '信号PINの変化イベント AddHandler Me.SerialPort.PinChanged, AddressOf PinChangedHandler End Sub ''' ----------------------------------------------------------------------- '''''' 最終受信データプロパティ ''' '''受信データ文字列 ''' ----------------------------------------------------------------------- ReadOnly Property LastRxData As String Get Return Me.strLastRxData End Get End Property ''' ----------------------------------------------------------------------- '''''' ポートオープン ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Open() As Boolean '戻り値初期化 Open = False Try 'ポートチェック If Me.SerialPort.IsOpen = False Then '未オープンならば、オープンする 'ポート設定(ここは通信相手に合わせる) Me.SerialPort.PortName = "COM7" Me.SerialPort.BaudRate = 9600 Me.SerialPort.DataBits = 8 Me.SerialPort.Parity = Parity.None Me.SerialPort.StopBits = StopBits.One '制御信号のON Me.SerialPort.DtrEnable = True 'DTR(Data Terminal Ready) Me.SerialPort.RtsEnable = True 'RTS(Request To Send) 'オープン Me.SerialPort.Open() End If '結果を返す Open = Me.SerialPort.IsOpen Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' ポートクローズ ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Close() As Boolean '戻り値初期化 Close = False Try 'ポートチェック If Me.SerialPort.IsOpen = True Then 'オープン済みならば、クローズする Me.SerialPort.Close() End If '結果を返す Close = Not (Me.SerialPort.IsOpen) Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' データ受信ハンドラ ''' '''''' [STX]から始まるデータをコマンドバッファに格納し[ETX]受信時に文字列に変換 ''' ''' ----------------------------------------------------------------------- Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs) Try Dim SP As SerialPort = CType(sender, SerialPort) 'バッファのバイト数チェック Dim DataLen As Integer = SP.BytesToRead If DataLen = 0 Then Exit Sub End If 'データ長チェック If DataLen > 4096 Then DataLen = 4096 End If '読込バッファの確保 Dim Buf(DataLen - 1) As Byte '読込 SP.Read(Buf, 0, DataLen) ' '受信バッファを先頭からチェックする For i As Integer = 0 To Buf.Length - 1 Select Case Buf(i) Case CMD_STX If Me.fSTX = True Then '再度のSTXはコマンドバッファをクリア Me.CmdBuf = Nothing End If 'STXフラグON Me.fSTX = True Case CMD_ETX If Me.fSTX = True Then 'STXフラグONの場合 'コマンドバッファを文字列変換(最終受信文字列に退避) Me.strLastRxData = System.Text.Encoding.GetEncoding(932).GetString(Me.CmdBuf) '*** データ受信イベントを発生 *** Dim se As New SerialEventArgs se.ReceivedData = Me.strLastRxData '受信データの値をセット RaiseEvent ReceivedData(Me, se) 'STXフラグOFF Me.fSTX = False End If 'コマンドバッファクリア Me.CmdBuf = Nothing Case Else '[STX][ETX]以外 If Me.fSTX = True Then 'STXフラグONの場合 Dim intIdx As Integer = 0 If Me.CmdBuf Is Nothing Then '格納バッファの領域確保 Me.CmdBuf = Array.CreateInstance(GetType(Byte), 1) '先頭指定 intIdx = 0 Else '後ろに追加する Dim Length As Integer = Me.CmdBuf.Length ReDim Preserve Me.CmdBuf(Length) '最後尾指定 intIdx = Length End If '1文字コピー Me.CmdBuf(intIdx) = Buf(i) End If End Select Next Catch ex As Exception 'エラー処理 End Try End Sub ''' ----------------------------------------------------------------------- '''''' 信号PIN変化ハンドラ ''' ''' ----------------------------------------------------------------------- Private Sub PinChangedHandler(sender As Object, e As SerialPinChangedEventArgs) Try '信号PIN変化判別 Select Case e.EventType Case SerialPinChange.CtsChanged 'CTSのPinが変更された場合、CTS信号イベントを発生 Dim se As New SerialCTSChangeEventArgs se.CTS = Me.SerialPort.CtsHolding '信号値をセット RaiseEvent CTSChanged(Me, se) Case SerialPinChange.DsrChanged 'DSRのPinが変更された場合、CTS信号イベントを発生 Dim se As New SerialDSRChangeEventArgs se.DSR = Me.SerialPort.DsrHolding '信号値をセット RaiseEvent DSRChanged(Me, se) End Select Catch ex As Exception 'エラー処理 End Try End Sub End Class
このクラスを使用した例を以下のソースに示します。
SerialPortコントロールの使い方その4(通信用クラスの使用例)
Public Class frmSerialRcvEvent2 'シリアル通信クラス Private WithEvents mclsSerialRcv As ClsSerialRcvEvent2 'Invokeメソッドで使用するデリゲート宣言 Delegate Sub DisplayTextDelegate(ByVal strDisp As String) 'Invokeメソッドで使用するデリゲート宣言 Delegate Sub SetSignalLabelDelegate(lblSig As Label, ByVal blnSig As Boolean) '''
''' フォームクローズイベント ''' Private Sub frmSerialRcv_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed 'シリアル通信のクローズ mclsSerialRcv.Close() End Sub '''''' フォームロードイベント ''' Private Sub frmSerialRcv_Load(sender As Object, e As EventArgs) Handles Me.Load 'CTS,DSR信号ラベルOFF SetSignalLabel(Me.lblCTS, False) SetSignalLabel(Me.lblDSR, False) 'シリアル通信クラスの生成 mclsSerialRcv = New ClsSerialRcvEvent2(Me.SerialPort1) 'シリアル通信のオープン If mclsSerialRcv.Open() = False Then 'オープンエラー(必要があれば処理する) End If End Sub '''''' リッチテキストBOXに文字列表示関数 ''' ''' <param name="strDisp">表示文字列</param> Private Sub DisplayText(ByVal strDisp As String) 'リッチテキストBOXに文字列を追加 Me.RichTextBox1.Text &= strDisp & vbCrLf End Sub '''''' データ受信のイベント処理(この処理は別スレッドでコールされる!!) ''' Private Sub mclsSerialRcv_ReceivedData(sender As Object, e As SerialEventArgs) Handles mclsSerialRcv.ReceivedData Try 'データ表示:デリゲート生成 Dim dlg As New DisplayTextDelegate(AddressOf DisplayText) 'デリゲート関数をコールする Me.Invoke(dlg, New Object() {e.ReceivedData}) Catch ex As Exception MsgBox(ex.Message) End Try End Sub '''''' CTS信号イベント処理 ''' Private Sub mclsSerialRcv_CTSChanged(sender As Object, e As SerialCTSChangeEventArgs) Handles mclsSerialRcv.CTSChanged Try 'CTS信号ラベル表示:デリゲート生成 Dim dlg As New SetSignalLabelDelegate(AddressOf SetSignalLabel) 'デリゲート関数をコールする Me.Invoke(dlg, New Object() {Me.lblCTS, e.CTS}) Catch ex As Exception MsgBox(ex.Message) End Try End Sub '''''' DSR信号イベント処理 ''' Private Sub mclsSerialRcv_DSRChanged(sender As Object, e As SerialDSRChangeEventArgs) Handles mclsSerialRcv.DSRChanged Try 'DSR信号ラベル表示:デリゲート生成 Dim dlg As New SetSignalLabelDelegate(AddressOf SetSignalLabel) 'デリゲート関数をコールする Me.Invoke(dlg, New Object() {Me.lblDSR, e.DSR}) Catch ex As Exception MsgBox(ex.Message) End Try End Sub Private Sub SetSignalLabel(lblSig As Label, ByVal blnSig As Boolean) Try If blnSig = True Then lblSig.Text = "ON" lblSig.BackColor = Color.Yellow Else lblSig.Text = "OFF" lblSig.BackColor = SystemColors.Control End If Catch ex As Exception MsgBox(ex.Message) End Try End Sub End Class
このフォームは、シリアルコントロール及び、受信データ表示用のリッチテキストボックスを画面に張り付けてあります。 シリアル通信クラスを WithEvents で宣言し、データ受信イベントの関数宣言が出来る様にします。 その関数 mclsSerialRcv_ReceivedData 中で、受信データの処理を行います。
尚、追加で CTS DSR の信号状態を表示する為のラベルを設置しています。 CTS DSR の信号イベントでこのラベルの状態を変化させるため、 デリゲート処理でラベルの Text と BackColor の値を設定しています。
以下はプログラムを起動した後で、機器側の制御信号をOFFのままにしています。
以下は機器側の制御信号 CTS DSR をONし、データを送信した結果です。USB ⇒ RS232C 変換ケーブル
シリアル通信に関連してですが、 最近のPC、特にノートPCの場合ではRS232Cのコネクタがついていることは殆んどありません。
そのため、以下の様なUSBを使ったRS232Cの変換ケーブルが使えそうです。
⇒iBUFFALO USBシリアルケーブル(USBtypeA to D-sub9ピン)1.0m ブラックスケルトン BSUSRC0610BS
⇒サンワサプライ USB-RS232Cコンバータ USB-CVRS9
⇒Plugable USB‐9ピンRS232シリアルアダプター (Prolific社製 PL2303HX Rev Dチップセット採用)
関連する記事
⇒SerialPortコントロールの使用方法:[SerialPort,Invoke]
⇒SerialPortコントロールの使い方その2
⇒SerialPortコントロールの使い方その3(外部装置からの垂れ流しデータ受信)
⇒SerialPortコントロールの使い方その4(データ受信時にイベントを発生させる)
⇒SerialPortコントロールの使い方その6(ハンドシェィクによるデータ送受信)
PR -
前回のSerialPortコントロールを使い方その3では、外部装置から「垂れ流し」的にデータが向こうからやってくる場合 を想定していました。
メイン処理側ではタイマイベントにより一定の時間ごとに受信があったかどうかをみて処理を行っていましたが、この方法はあまりスマートではありません。 そこで、データを受信した時のみ処理が出来る様に、メイン側にイベントとして通知する方法を考えてみました。
イベントと言えば以下の様にテキストボックスの KeyPress イベントなどがあります。 関数宣言の第2引数の KeyPressEventArgs を通して入力されたキーデータが通知されます。
今回はデータ受信イベントなので、イベント関数の第2引数の KeyPressEventArgs を受信用のものに変え 受信データを通知する様にします。Private Sub KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
先ずはイベント発生時のアーギュメントの宣言ですが、以下の様なクラスです。 イベントアーギュメントの元クラスの EventArgs を継承し SerialEventArgs と宣言します。 追加するプロパティとして文字列の受信データのやり取りを宣言します。
データ受信イベント・通知アーギュメント用クラス
Public Class SerialEventArgs Inherits EventArgs Private mstrReceivedData As String ' 受信データを取得 Public Property ReceivedData() As String Get Return mstrReceivedData End Get Set(ByVal value As String) mstrReceivedData = value End Set End Property End Class
この通知アーギュメントクラスを利用して、「その3」のシリアル通信クラスを変更します。 変更内容は以下の通りです。- Event を使ってイベントを定義を行う。
- 通知アーギュメントクラスを生成し、受信データをその中に設定する。
- データの終了コードを受信した時に、RaiseEvent を使ってイベントを発生する。
SerialPortコントロールの使い方その4(通信用クラス)
Imports System.IO.Ports ''' ----------------------------------------------------------------------- '''
''' シリアル通信クラス・垂れ流し受信イベント付き ''' ''' ----------------------------------------------------------------------- Public Class ClsSerialRcv '''''' シリアルポートクラス ''' Private SerialPort As SerialPort '''''' 読込データ格納先 ''' '''データ受信イベントで蓄えられる Private CmdBuf() As Byte '''''' STX受信フラグ(装置の送信が開始された証拠) ''' Private fSTX As Boolean = False '''''' 最終受信文字列(受信データからSTX,ETXを除いたもの) ''' Private strLastRxData As String = "" '''''' 送受信文字列の開始コード(STX:0x02) ''' Private Const CMD_STX As Byte = &H2 '''''' 送受信文字列の終了コード(ETX:0x03) ''' Private Const CMD_ETX As Byte = &H3 '''''' データ受信イベント定義 ''' Public Event ReceivedData(ByVal sender As Object, ByVal e As SerialEventArgs) ''' ----------------------------------------------------------------------- '''''' コンストラクタ ''' ''' <param name="SerialPort">シリアルポートコントロール</param> ''' ----------------------------------------------------------------------- Sub New(ByVal SerialPort As SerialPort) 'シリアルポートの退避 Me.SerialPort = SerialPort '受信イベントのハンドラ設定 AddHandler Me.SerialPort.DataReceived, AddressOf DataReceivedHandler End Sub ''' ----------------------------------------------------------------------- '''''' 最終受信データプロパティ ''' '''受信データ文字列 ''' ----------------------------------------------------------------------- ReadOnly Property LastRxData As String Get Return Me.strLastRxData End Get End Property ''' ----------------------------------------------------------------------- '''''' ポートオープン ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Open() As Boolean '戻り値初期化 Open = False Try 'ポートチェック If Me.SerialPort.IsOpen = False Then '未オープンならば、オープンする 'ポート設定(ここは通信相手に合わせる) Me.SerialPort.PortName = "COM7" Me.SerialPort.BaudRate = 9600 Me.SerialPort.DataBits = 8 Me.SerialPort.Parity = Parity.None Me.SerialPort.StopBits = StopBits.One 'オープン Me.SerialPort.Open() End If '結果を返す Open = Me.SerialPort.IsOpen Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' ポートクローズ ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Close() As Boolean '戻り値初期化 Close = False Try 'ポートチェック If Me.SerialPort.IsOpen = True Then 'オープン済みならば、クローズする Me.SerialPort.Close() End If '結果を返す Close = Not (Me.SerialPort.IsOpen) Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' データ受信ハンドラ ''' '''''' [STX]から始まるデータをコマンドバッファに格納し[ETX]受信時に文字列に変換 ''' ''' ----------------------------------------------------------------------- Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs) Try Dim SP As SerialPort = CType(sender, SerialPort) 'バッファのバイト数チェック Dim DataLen As Integer = SP.BytesToRead If DataLen = 0 Then Exit Sub End If 'データ長チェック If DataLen > 4096 Then DataLen = 4096 End If '読込バッファの確保 Dim Buf(DataLen - 1) As Byte '読込 SP.Read(Buf, 0, DataLen) ' '受信バッファを先頭からチェックする For i As Integer = 0 To Buf.Length - 1 Select Case Buf(i) Case CMD_STX If Me.fSTX = True Then '再度のSTXはコマンドバッファをクリア Me.CmdBuf = Nothing End If 'STXフラグON Me.fSTX = True Case CMD_ETX If Me.fSTX = True Then 'STXフラグONの場合 'コマンドバッファを文字列変換 Me.strLastRxData = _ System.Text.Encoding.GetEncoding(932).GetString(Me.CmdBuf) '*** データ受信イベントを発生 *** Dim se As New SerialEventArgs se.ReceivedData = Me.strLastRxData '受信データの値をセット RaiseEvent ReceivedData(Me, se) 'STXフラグOFF Me.fSTX = False End If 'コマンドバッファクリア Me.CmdBuf = Nothing Case Else '[STX][ETX]以外 If Me.fSTX = True Then 'STXフラグONの場合 Dim intIdx As Integer = 0 If Me.CmdBuf Is Nothing Then '格納バッファの領域確保 Me.CmdBuf = Array.CreateInstance(GetType(Byte), 1) '先頭指定 intIdx = 0 Else '後ろに追加する Dim Length As Integer = Me.CmdBuf.Length ReDim Preserve Me.CmdBuf(Length) '最後尾指定 intIdx = Length End If '1文字コピー Me.CmdBuf(intIdx) = Buf(i) End If End Select Next Catch ex As Exception 'エラー処理 End Try End Sub End Class
このクラスを使用した例を以下のソースに示します。
SerialPortコントロールの使い方その4(通信用クラスの使用例)
Public Class frmSerialRcvEvent 'シリアル通信クラス Private WithEvents mclsSerialRcv As ClsSerialRcvEvent 'Invokeメソッドで使用するデリゲート宣言 Delegate Sub DisplayTextDelegate(ByVal strDisp As String) '''
''' フォームクローズイベント ''' Private Sub frmSerialRcv_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed 'シリアル通信のクローズ mclsSerialRcv.Close() End Sub '''''' フォームロードイベント ''' Private Sub frmSerialRcv_Load(sender As Object, e As EventArgs) Handles Me.Load 'シリアル通信クラスの生成 mclsSerialRcv = New ClsSerialRcvEvent(Me.SerialPort1) 'シリアル通信のオープン If mclsSerialRcv.Open() = False Then 'オープンエラー(必要があれば処理する) End If End Sub '''''' リッチテキストBOXに文字列表示関数 ''' ''' <param name="strDisp">表示文字列</param> Private Sub DisplayText(ByVal strDisp As String) 'リッチテキストBOXに文字列を追加 Me.RichTextBox1.Text &= strDisp & vbCrLf End Sub '''''' データ受信のイベント処理(この処理は別スレッドでコールされる!!) ''' Private Sub mclsSerialRcv_ReceivedData(sender As Object, e As SerialEventArgs) Handles mclsSerialRcv.ReceivedData Try '以下の処理はスレッドが異なると怒られます。 'Me.RichTextBox1.Text &= e.ReceivedData & vbCrLf 'データ表示:デリゲート生成 Dim dlg As New DisplayTextDelegate(AddressOf DisplayText) 'デリゲート関数をコールする Me.Invoke(dlg, New Object() {e.ReceivedData}) Catch ex As Exception MsgBox(ex.Message) End Try End Sub End Class
このフォームは、シリアルコントロール及び、受信データ表示用のリッチテキストボックスを画面に張り付けてあります。 シリアル通信クラスを WithEvents で宣言し、データ受信イベントの関数宣言が出来る様にします。 その関数 mclsSerialRcv_ReceivedData 中で、受信データの処理を行います。
このイベント処理は注意が必要で、自分のフォーム内のコントロールには直接アクセスが出来ません。
この mclsSerialRcv_ReceivedData は元をたどれば、シリアルコントロールのイベント DataReceived の中から呼ばれるので 別スレッドになるからです。
そこで「SerialPortコントロールの使用方法:[SerialPort,Invoke]」と同様にデリゲート宣言を行って Invoke 関数でそれをコールする必要があります。
このプログラムを実行すると、以下の様に、「RS232Cテストツール」から連続で2個のデータを送信しても、 それぞれのデータが表示されます。- <STX>DATA=2002<ETX><STX>DATA=3333<ETX>
USB ⇒ RS232C 変換ケーブル
シリアル通信に関連してですが、 最近のPC、特にノートPCの場合ではRS232Cのコネクタがついていることは殆んどありません。
そのため、以下の様なUSBを使ったRS232Cの変換ケーブルが使えそうです。
⇒iBUFFALO USBシリアルケーブル(USBtypeA to D-sub9ピン)1.0m ブラックスケルトン BSUSRC0610BS
⇒サンワサプライ USB-RS232Cコンバータ USB-CVRS9
⇒Plugable USB‐9ピンRS232シリアルアダプター (Prolific社製 PL2303HX Rev Dチップセット採用)
関連する記事
⇒クラスにイベントを実装する方法について(Event, RaiseEvent, WithEvents)
⇒SerialPortコントロールの使用方法:[SerialPort,Invoke]
⇒SerialPortコントロールの使い方その2
⇒SerialPortコントロールの使い方その3(外部装置からの垂れ流しデータ受信)
⇒SerialPortコントロールの使い方その5(データ受信時及び、信号変化時にイベントを発生させる)
⇒SerialPortコントロールの使い方その6(ハンドシェィクによるデータ送受信)
おすすめ本
-
前回のSerialPortコントロールを使い方その2では、 最初にこちら側からデータを送信し、その後で装置側からのデータ受信を行うことを想定していました。
⇒SerialPortコントロールの使い方その2
しかし、外部装置でもコマンドのハンドシェイクを行わないで、常にデータを送信してくるものもあります。
表現としては汚いのですが、いわゆる「垂れ流し」的にデータが向こうからやってくる場合があります。 今回はこの様な場合を想定した「垂れ流し」受信専門のクラスを作成してみます。
「その2」のクラスと初期化・終了処理は全く同様ですが、今回はデータ受信時のイベント処理が変更されています。 クラスの概要は以下の通りです。- 外部装置との通信は調歩同期とし、Shift-JIS文字列での送受信を対象とする。
- 通信ポート設定は「ボーレート:9600BPS、データビット:8、パリティビット:無し、ストップビット:1」とする。
- 送受信文字列の開始コードは「STX:0x02」、終了コードは「ETX:0x03」とする。
- 外部装置からのデータは常に「STX」「ETX」の間にデータがはさまれているとする。
- 受信文字列は4096バイトのバッファで行う。
SerialPortコントロールの使い方その3(通信用クラス)
Imports System.IO.Ports ''' ----------------------------------------------------------------------- '''
''' シリアル通信クラス ''' ''' ----------------------------------------------------------------------- Public Class ClsSerialRcv '''''' シリアルポートクラス ''' Private SerialPort As SerialPort '''''' 読込データ格納先 ''' '''データ受信イベントで蓄えられる Private CmdBuf() As Byte '''''' STX受信フラグ(装置の送信が開始された証拠) ''' Private fSTX As Boolean = False '''''' 最終受信文字列(受信データからSTX,ETXを除いたもの) ''' Private strLastRxData As String = "" '''''' 送受信文字列の開始コード(STX:0x02) ''' Private Const CMD_STX As Byte = &H2 '''''' 送受信文字列の終了コード(ETX:0x03) ''' Private Const CMD_ETX As Byte = &H3 ''' ----------------------------------------------------------------------- '''''' コンストラクタ ''' ''' <param name="SerialPort">シリアルポートコントロール</param> ''' ----------------------------------------------------------------------- Sub New(ByVal SerialPort As SerialPort) 'シリアルポートの退避 Me.SerialPort = SerialPort '受信イベントのハンドラ設定 AddHandler Me.SerialPort.DataReceived, AddressOf DataReceivedHandler End Sub ''' ----------------------------------------------------------------------- '''''' 最終受信データプロパティ ''' '''受信データ文字列 ''' ----------------------------------------------------------------------- ReadOnly Property LastRxData As String Get Return Me.strLastRxData End Get End Property ''' ----------------------------------------------------------------------- '''''' ポートオープン ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Open() As Boolean '戻り値初期化 Open = False Try 'ポートチェック If Me.SerialPort.IsOpen = False Then '未オープンならば、オープンする 'ポート設定(ここは通信相手に合わせる) Me.SerialPort.PortName = "COM7" Me.SerialPort.BaudRate = 9600 Me.SerialPort.DataBits = 8 Me.SerialPort.Parity = Parity.None Me.SerialPort.StopBits = StopBits.One 'オープン Me.SerialPort.Open() End If '結果を返す Open = Me.SerialPort.IsOpen Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' ポートクローズ ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Close() As Boolean '戻り値初期化 Close = False Try 'ポートチェック If Me.SerialPort.IsOpen = True Then 'オープン済みならば、クローズする Me.SerialPort.Close() End If '結果を返す Close = Not (Me.SerialPort.IsOpen) Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' データ受信ハンドラ ''' '''''' [STX]から始まるデータをコマンドバッファに格納し[ETX]受信時に文字列に変換 ''' ''' ----------------------------------------------------------------------- Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs) Try Dim SP As SerialPort = CType(sender, SerialPort) 'バッファのバイト数チェック Dim DataLen As Integer = SP.BytesToRead If DataLen = 0 Then Exit Sub End If 'データ長チェック If DataLen > 4096 Then DataLen = 4096 End If '読込バッファの確保 Dim Buf(DataLen - 1) As Byte '読込 SP.Read(Buf, 0, DataLen) ' '受信バッファを先頭からチェックする For i As Integer = 0 To Buf.Length - 1 Select Case Buf(i) Case CMD_STX If Me.fSTX = True Then '再度のSTXはコマンドバッファをクリア Me.CmdBuf = Nothing End If 'STXフラグON Me.fSTX = True Case CMD_ETX If Me.fSTX = True Then 'STXフラグONの場合 'コマンドバッファを文字列変換 Me.strLastRxData = _ System.Text.Encoding.GetEncoding(932).GetString(Me.CmdBuf) 'STXフラグOFF Me.fSTX = False End If 'コマンドバッファクリア Me.CmdBuf = Nothing Case Else '[STX][ETX]以外 If Me.fSTX = True Then 'STXフラグONの場合 Dim intIdx As Integer = 0 If Me.CmdBuf Is Nothing Then '格納バッファの領域確保 Me.CmdBuf = Array.CreateInstance(GetType(Byte), 1) '先頭指定 intIdx = 0 Else '後ろに追加する Dim Length As Integer = Me.CmdBuf.Length ReDim Preserve Me.CmdBuf(Length) '最後尾指定 intIdx = Length End If '1文字コピー Me.CmdBuf(intIdx) = Buf(i) End If End Select Next Catch ex As Exception 'エラー処理 End Try End Sub End Class
データ受信ハンドラでは、「STX」を受信するまでは受信されたデータを対象としていません。 「STX」受信でフラグをONし、そのフラグを見てONしていれば受信されたデータを対象とします。 「ETX」受信でも「STX」受信フラグがOFFであれば、「ETX」の処理は行いません。
このクラスを使用した例を以下のソースに示します。
SerialPortコントロールの使い方その3(通信用クラスの使用例)
Public Class frmSerialRcv 'シリアル通信クラス Private mclsSerialRcv As ClsSerialRcv '前回受信データ Private mstrLastData As String '''
''' フォームクローズイベント ''' Private Sub frmSerialRcv_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed 'シリアル通信のクローズ mclsSerialRcv.Close() End Sub '''''' フォームロードイベント ''' Private Sub frmSerialRcv_Load(sender As Object, e As EventArgs) Handles Me.Load 'シリアル通信クラスの生成 mclsSerialRcv = New ClsSerialRcv(Me.SerialPort1) 'シリアル通信のオープン If mclsSerialRcv.Open() = False Then 'オープンエラー(必要があれば処理する) End If 'タイマ設定 Me.Timer1.Interval = 100 '100msec Me.Timer1.Enabled = True End Sub '''''' 100msec毎のタイマ処理 ''' Private Sub Timer1_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles Timer1.Elapsed '最終受信データ取得 Dim strLastData As String = Me.mclsSerialRcv.LastRxData '前回処理データとの比較 If strLastData <> Me.mstrLastData Then 'データ表示 Me.RichTextBox1.Text &= strLastData & vbCrLf '前回値へ退避 Me.mstrLastData = strLastData End If End Sub End Class
このフォームは、シリアルコントロールとタイマコントロール及び、受信データ表示用のリッチテキストボックスを画面に張り付けてあります。
タイマコントロールのイベントは100msec毎に発生させて、受信データが変化したかを判定し、変化が在った場合にリッチテキストボックスに表示しています。
通信相手のシミュレーションとしてフリーソフトの「RS232Cテストツール」を使用しています。 VBのプログラムを実行後、「RS232Cテストツール」を起動します。「RS232Cテストツール」で「起動」ボタン押下後、 「送信TEXT」のボックスに送信文字列を入力し、「TEXT送信」ボタン押下で文字列が送信されます。
上図は以下の文字列を送信しています。- <STX>DATA=1001<ETX>
- <STX>DATA=2002<ETX>
- <STX>DATA=3003<ETX>
尚、特殊な例として以下の文字列を送信すると(後ろの ETX を送信していません)
- <STX>DATA=4004<ETX><STX>DATA=5555
内部的に「DATA=5555」が保留されています。
その後、 ETX のみを送信すると、最後のデータが表示されます。
- <ETX>
以下は「その2」でも載せていますが、今回も、通信相手用の仮想シリアルポートとしてcom0com というドライバを使用し、 2個のシリアルポートを作成し、ループバックで接続しています。 今回のプログラムをテストするためには外部装置か、もう一台別のPCが必要になりますが、 そんなことをしなくてもデバッグができるソフト(ドライバ)が在ります。
com0com というドライバで、PC上に仮想シリアルポートを2個作成し、 その2個をループバックできる様に仮想的に接続できるという優れものです。 以下のリンク先でソフトをダウンロードしてインストールしてみて下さい。 (尚、もう一台のPCなどがあれば必要ありませんが)
⇒「com0com ドライバ」
COM8側を通信相手側(外部装置)とするのですが、通信テスト用に以下のフリーソフトを使いました。
「のん」さんといわれる方が作成された「RS232Cテストツール」です。
以下のサイトにアクセスすれば、ダウンロードできます。
⇒「RS232Cテストツール」USB ⇒ RS232C 変換ケーブル
シリアル通信に関連してですが、 最近のPC、特にノートPCの場合ではRS232Cのコネクタがついていることは殆んどありません。
そのため、以下の様なUSBを使ったRS232Cの変換ケーブルが使えそうです。
⇒iBUFFALO USBシリアルケーブル(USBtypeA to D-sub9ピン)1.0m ブラックスケルトン BSUSRC0610BS
⇒サンワサプライ USB-RS232Cコンバータ USB-CVRS9
⇒Plugable USB‐9ピンRS232シリアルアダプター (Prolific社製 PL2303HX Rev Dチップセット採用)
関連する記事
⇒SerialPortコントロールの使用方法 :[SerialPort,Invoke]
⇒SerialPortコントロールの使い方その2
⇒SerialPortコントロールの使い方その4(データ受信時にイベントを発生させる)
⇒SerialPortコントロールの使い方その5(データ受信時及び、信号変化時にイベントを発生させる)
⇒SerialPortコントロールの使い方その6(ハンドシェィクによるデータ送受信)
おすすめ本
-
以前、テキストボックスコントロールを基底クラスとして、入力される文字を数字のみとするクラスを紹介しました。
⇒テキストボックスの入力を数字のみにする方法
今回は、入力が便利になる様なプロパティを追加してみたいと思います。
追加する機能は、以下の3個の機能です。- 自分自身にフォーカス移動が在った場合に、背景色を変更する。
- 自分自身にフォーカス移動が在った場合に、テキスト全体を選択状態にする。
- Enter キーによる次のタブストップが指定されているコントロールへのフォーカス移動。
最初の背景色の設定の為に、自分自身がアクティブである時の背景色と、 アクティブではない時の背景色を設定するプロパティを設定します。
クラスの静的変数にアクティブ時(_ActiveBackColor)と非アクティブ時(_InactiveBackColor)の背景色を持ちます。 さらに、この変数をアクセスするためのプロパティ宣言をそれぞれ、ActiveBackColor InactiveBackColor とします。
背景色を変える処理を、Enterイベントの処理の OnEnter 及び、Leaveイベントの処理の OnLeave で処理を行います。
また、フォーカスが移動してきた時の、テキスト全体を選択状態にする指示プロパティを ActiveSelectAll として宣言します。
実際の処理は、 OnEnter 内でこのフラグを見て、 True の場合に、テキストの全選択を行います。
以下にソースを示します。テキストボックス拡張クラスにプロパティを追加する方法
Public Class ClsNumTextBox2 Inherits TextBox 'アクティブ時の背景色 Private _ActiveBackColor As Color = Color.White '非アクティブ時の背景色 Private _InactiveBackColor As Color = Color.White 'アクティブ時の全選択フラグ Private _ActiveSelectAll As Boolean = False 'クリップボード貼付メッセージ Const WM_PASTE As Integer = &H302 '''
''' WndProc メソッド (override) ''' ''' <param name="m">メッセージ</param> Protected Overrides Sub WndProc(ByRef m As Message) Select Case m.Msg Case WM_PASTE Dim iDataObj As IDataObject = Clipboard.GetDataObject() 'クリップボードの中身があるか、かつ文字列に変換できるか?? If (iDataObj IsNot Nothing) And (iDataObj.GetDataPresent(DataFormats.Text) = True) Then '文字列に変換 Dim strClip As String = DirectCast(iDataObj.GetData(DataFormats.Text), String) '文字列が数字のみか調べる If Me.ChkClipString(strClip) = False Then Return End If End If End Select 'メッセージのデフォルト処理を呼出す MyBase.WndProc(m) End Sub '''''' コンストラクタ ''' Public Sub New() MyBase.New() 'IMEを無効にする MyBase.ImeMode = ImeMode.Disable End Sub '''''' アクティブ時の背景色 ''' Public Property ActiveBackColor As Color Set(value As Color) _ActiveBackColor = value '退避値に設定 End Set Get Return _ActiveBackColor '退避値を返す End Get End Property '''''' 非アクティブ時の背景色 ''' Public Property InactiveBackColor As Color Set(value As Color) _InactiveBackColor = value '退避値に設定 End Set Get Return _InactiveBackColor '退避値を返す End Get End Property '''''' アクティブ時の全選択フラグ ''' Public Property ActiveSelectAll As Boolean Set(value As Boolean) _ActiveSelectAll = value '退避値に設定 End Set Get Return _ActiveSelectAll '退避値を返す End Get End Property '''''' Enterイベントの処理 ''' Protected Overrides Sub OnEnter(e As EventArgs) MyBase.OnEnter(e) '背景色の設定 Me.BackColor = Me._ActiveBackColor 'アクティブ時の全選択フラグ If Me._ActiveSelectAll = True Then Me.SelectAll() End If End Sub '''''' Leaveイベントの処理 ''' Protected Overrides Sub OnLeave(e As EventArgs) MyBase.OnLeave(e) '背景色の設定 Me.BackColor = Me._InactiveBackColor End Sub '''''' KeyPressイベントの処理 ''' Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs) MyBase.OnKeyPress(e) 'キーが [0]~[9] または [BackSpace] 以外の場合イベントをキャンセル If Not (("0"c <= e.KeyChar And e.KeyChar <= "9"c) Or e.KeyChar = ControlChars.Back) Then e.Handled = True End If End Sub '''''' 文字列のチェック関数 ''' ''' <param name="strClip">指定文字列</param> '''True:OK, False:NG Private Function ChkClipString(ByVal strClip As String) As Boolean ChkClipString = False If System.Text.RegularExpressions.Regex.IsMatch(strClip, "^[0-9]+$") Then Return True End If End Function '''''' KeyDownイベントの処理 ''' Protected Overrides Sub OnKeyDown(e As KeyEventArgs) MyBase.OnKeyDown(e) '[Enter]キーの場合 If e.KeyCode = Keys.Enter Then If e.Control = False Then '[Ctrl]キーが押下されていない場合、自分の親のコントロールの次のフォーカスへ移動 Me.Parent.SelectNextControl(Me, Not e.Shift, True, True, True) End If End If End Sub End Classこのソースを別のファイルで作成し、一度コンパイルします。 そうすると、ツールボックスの中に ClsNumTextBox2 が現れますので、以下の様にこれをフォーム上に貼り付けます。
ActiveBackColor にはYellow InactiveBackColor にはWhite を設定し、 ActiveSelectAll にはTrue と設定します。このフォームにはコードを何も記述していませんが、そのまま実行した結果は以下の様な感じです。
Enterキーを押下することで、フォーカスが順次移動し、背景が黄色になります。 テキストボックス内に文字列が入力されていれば、フォーカス移動時には選択状態になります。
関連する記事
⇒テキストボックスの入力を数字のみにする方法その2(電卓の様な入力)
⇒テキストボックスの Leave イベントでのエラー処理でフォーカス強制移動する方法について
-
SerialPortコントロールを使い方を以下の記事で紹介しましたが、 今回は外部装置との簡単な送受信ができるクラスの紹介を行います。
⇒SerialPortコントロールの使用方法:[SerialPort,Invoke]
クラスの概要は以下の通りです。- 外部装置との通信は調歩同期とし、Shift-JIS文字列での送受信を対象とする。
- 通信ポート設定は「ボーレート:9600BPS、データビット:8、パリティビット:無し、ストップビット:1」とする。
- 送受信文字列の終端文字は「CR:0xD」とする。
- 外部装置からのデータ受信は、最初にコマンド文字列を送信し、その後データ受信する手順とする。
- コマンド文字列送信後、約5秒以内にデータ受信できない場合はエラーとする。
- 受信文字列は4096バイトのバッファで行う。
SerialPortコントロールの使い方その2(通信用クラス)
Imports System.IO.Ports ''' ----------------------------------------------------------------------- '''
''' シリアル通信クラス ''' ''' ----------------------------------------------------------------------- Public Class ClsSerial '''''' シリアルポートクラス ''' '''Private SerialPort As SerialPort ''' ''' 読込データ格納先 ''' '''データ受信イベントで蓄えられる Private RxBuf() As Byte '''''' コマンド応答受信フラグ ''' '''''' コマンドを送信した後での応答を受信したフラグ。送受信文字列のターミネータ[CR](0x0d)を発見したとにオンする ''' Private fRxResponse As Boolean = False '''''' 送受信文字列のターミネータ(0x0d) ''' Private Const CMD_TERM As Byte = &HD ''' ----------------------------------------------------------------------- '''''' コンストラクタ ''' ''' <param name="SerialPort">シリアルポートコントロール</param> ''' ----------------------------------------------------------------------- Sub New(ByVal SerialPort As SerialPort) 'シリアルポートの退避 Me.SerialPort = SerialPort '受信イベントのハンドラ設定 AddHandler Me.SerialPort.DataReceived, AddressOf DataReceivedHandler End Sub ''' ----------------------------------------------------------------------- '''''' ポートオープン ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Open() As Boolean '戻り値初期化 Open = False Try 'ポートチェック If Me.SerialPort.IsOpen = False Then '未オープンならば、オープンする 'ポート設定(ここは通信相手に合わせる) Me.SerialPort.PortName = "COM7" Me.SerialPort.BaudRate = 9600 Me.SerialPort.DataBits = 8 Me.SerialPort.Parity = Parity.None Me.SerialPort.StopBits = StopBits.One 'オープン Me.SerialPort.Open() End If '結果を返す Open = Me.SerialPort.IsOpen Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' ポートクローズ ''' '''True:正常終了, False:エラー ''' ----------------------------------------------------------------------- Function Close() As Boolean '戻り値初期化 Close = False Try 'ポートチェック If Me.SerialPort.IsOpen = True Then 'オープン済みならば、クローズする Me.SerialPort.Close() End If '結果を返す Close = Not (Me.SerialPort.IsOpen) Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' データ受信ハンドラ ''' ''' ----------------------------------------------------------------------- Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs) Try Dim SP As SerialPort = CType(sender, SerialPort) 'バッファのバイト数チェック Dim DataLen As Integer = SP.BytesToRead If DataLen = 0 Then Exit Sub End If 'データ長チェック If DataLen > 4096 Then DataLen = 4096 End If '読込バッファの確保 Dim Buf(DataLen) As Byte '読込 SP.Read(Buf, 0, DataLen) ' If RxBuf Is Nothing Then '格納バッファの領域確保 RxBuf = Array.CreateInstance(GetType(Byte), DataLen) 'コピー Array.Copy(Buf, RxBuf, DataLen) Else '後ろに追加する Dim Length As Integer = RxBuf.Length ReDim Preserve RxBuf(Length + DataLen - 1) Buf.CopyTo(RxBuf, Length) End If '格納先の最後の文字が「CR」(0x0d)か確認する If RxBuf(UBound(RxBuf)) = CMD_TERM Then 'コマンド応答受信フラグON Me.fRxResponse = True End If Catch ex As Exception 'エラー処理 End Try End Sub ''' ----------------------------------------------------------------------- '''''' コマンド送信・レスポンス受信処理 ''' ''' <param name="strCmd">コマンド文字列</param> ''' <param name="strRsv">レスポンス文字列</param> '''応答受信結果(True:OK, False:NG) ''' ----------------------------------------------------------------------- Public Function SendCmdGetRsv(ByVal strCmd As String, ByRef strRsv As String) As Boolean '戻り値初期化 SendCmdGetRsv = False Try 'コマンド送信 If Me.SendData(strCmd) = False Then Return False End If 'コマンド受信 Dim strRX As String = "" If Me.ReceiveData(strRX) = False Then Return False End If strRsv = strRX '正常を返す Return True Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' コマンド送信 ''' ''' <param name="strSend">送信文字列</param> '''送信結果(True:OK, False:NG) ''' ----------------------------------------------------------------------- Private Function SendData(ByVal strSend As String) As Boolean '戻り値初期化 SendData = False Try 'ポートオープンチェック If Me.SerialPort.IsOpen = False Then Return False End If 'Shift JISとしてバイト型配列に変換 Dim bytesData As Byte() bytesData = System.Text.Encoding.GetEncoding(932).GetBytes(strSend) 'CRの1バイト分領域拡張 Dim nIdx As Integer = UBound(bytesData) ReDim Preserve bytesData(nIdx + 1) bytesData(nIdx + 1) = CMD_TERM 'コマンド応答受信フラグOFF Me.fRxResponse = False 'コマンド送信 Me.RxBuf = Nothing '受信バッファのクリア Me.SerialPort.Write(bytesData, 0, bytesData.Length) '正常 Return True Catch ex As Exception 'エラー処理 End Try End Function ''' ----------------------------------------------------------------------- '''''' レスポンス受信処理 ''' ''' <param name="RcvRes">受信レスポンス</param> '''受信結果(True:OK, False:NG) ''' ----------------------------------------------------------------------- Private Function ReceiveData(ByRef RcvRes As String) As Boolean '戻り値初期化 ReceiveData = False Try 'リトライ件数 Dim nRetry As Integer = 50 '50×100msec=5sec While nRetry > 0 System.Threading.Thread.Sleep(100) Application.DoEvents() If Me.fRxResponse = True Then '受信フラグONの場合、ループを抜ける Exit While End If 'リトライカウンタ-- nRetry -= 1 End While '----- 'タイムアウトチェック '----- If nRetry = 0 Then 'タイムアウトエラー Return False End If '受信バイトを文字列変換 Dim strRx As String = System.Text.Encoding.GetEncoding(932).GetString(Me.RxBuf) strRx = strRx.Substring(0, strRx.Length - 1) '最後の「CR」は省く '----- '受信データ処理 '----- '以下の処理などが在れば記述 '・BCC等のチェック処理 '・レスポンスチェック処理(送信側のエラーメッセージ等) '----- '受信レスポンスを返す RcvRes = strRx '結果正常 Return True Catch ex As Exception 'エラー処理 End Try End Function End Class
突っ込みどころが満載なクラスですが、簡単なコマンドを送信し、レスポンスを受信するぐらいであれば使用できると思います。
尚、受信イベントでの処理で、受信バッファを4096に限定していますので、この辺りを改良してみて下さい。
また、レスポンスの受信データをそのまま返していますが、エラー処理などは通信先の装置に合わせて下さい。
このクラスを使用した例を以下のソースに示します。
SerialPortコントロールの使い方その2(通信用クラスの使用例)
Public Class frmSerial2 'シリアル通信クラス Private mclsSerial As ClsSerial '''
''' フォームクローズイベント ''' Private Sub frmSerial2_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed 'シリアル通信のクローズ mclsSerial.Close() End Sub '''''' フォームロードイベント ''' Private Sub frmSerial2_Load(sender As Object, e As EventArgs) Handles Me.Load 'シリアル通信クラスの生成 mclsSerial = New ClsSerial(Me.SerialPort1) 'シリアル通信のオープン If mclsSerial.Open() = False Then 'オープンエラー(必要があれば処理する) End If End Sub '''''' [コマンド送信]クリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'レスポンス表示クリア Me.TextBox2.Text = "" 'コマンド取得 Dim strCmd As String = Me.TextBox1.Text.Trim If strCmd <> "" Then Dim strRsv As String = "" If Me.mclsSerial.SendCmdGetRsv(strCmd, strRsv) = True Then '正常受信、レスポンス表示 Me.TextBox2.Text = strRsv Else 'エラー Me.TextBox2.Text = "エラー発生" End If End If End Sub End Class
このフォームは、送信用の文字列を入力する TextBox と、受信結果を表示する TextBox を画面に張り付け、 通信の処理をさせるボタンを張り付けてあります。
実行の様子を下図に示します。
送信する文字列を 送信コマンド: TextBox に入力し、「コマンド送信」ボタンを押下します。
「RS232Cテストツール」側でコマンドの受信を確認して、「TEXT送信」ボタンを押下しますと、 受信レスポンス: TextBox にデータが表示されます。
(尚、通信相手のシミュレーションとしてフリーソフトの「RS232Cテストツール」を使用しています。)
尚、通信相手用の仮想シリアルポートとしてcom0com というドライバを使用し、 2個のシリアルポートを作成し、ループバックで接続しています。 今回のプログラムをテストするためには外部装置か、もう一台別のPCが必要になりますが、 そんなことをしなくてもデバッグができるソフト(ドライバ)が在ります。
com0com というドライバで、PC上に仮想シリアルポートを2個作成し、 その2個をループバックできる様に仮想的に接続できるという優れものです。 以下のリンク先でソフトをダウンロードしてインストールしてみて下さい。 (尚、もう一台のPCなどがあれば必要ありませんが)
⇒「com0com ドライバ」
COM8側を通信相手側(外部装置)とするのですが、通信テスト用に以下のフリーソフトを使いました。
「のん」さんといわれる方が作成された「RS232Cテストツール」です。
以下のサイトにアクセスすれば、ダウンロードできます。
⇒「RS232Cテストツール」USB ⇒ RS232C 変換ケーブル
シリアル通信に関連してですが、 最近のPC、特にノートPCの場合ではRS232Cのコネクタがついていることは殆んどありません。
そのため、以下の様なUSBを使ったRS232Cの変換ケーブルが使えそうです。
⇒iBUFFALO USBシリアルケーブル(USBtypeA to D-sub9ピン)1.0m ブラックスケルトン BSUSRC0610BS
⇒サンワサプライ USB-RS232Cコンバータ USB-CVRS9
⇒Plugable USB‐9ピンRS232シリアルアダプター (Prolific社製 PL2303HX Rev Dチップセット採用)
関連する記事
⇒SerialPortコントロールの使用方法 :[SerialPort,Invoke]
⇒SerialPortコントロールの使い方その3(外部装置からの垂れ流しデータ受信)
⇒SerialPortコントロールの使い方その4(データ受信時にイベントを発生させる)
⇒SerialPortコントロールの使い方その5(データ受信時及び、信号変化時にイベントを発生させる)
⇒SerialPortコントロールの使い方その6(ハンドシェィクによるデータ送受信)
おすすめ本