忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

SerialPortコントロールの使い方

最近では通信と言えば、BlueTooth, USBやネットでの通信が当たり前で、 シリアルポート(RS232C)を使って外部装置と通信することも少なくなりました。 しかし稀に外部装置との接続をシリアル通信(調歩同期)で行うこともありますので 今回はシリアルポートを使う方法を説明します。

SerialPortコントロールを使うには、フォーム上にツールボックスからSerialPortを選択し貼り付けます。 以下の図は、SerialPortコントロールを貼り付けた後の様子です。


MSDNの説明によれば以下の様になっています。(代表的なものを示しています。青色は今回使用しているものです。)

SerialPort コントロール・について

<プロパティ>
・PortName    :通信用のポートを取得または設定します。
                このポートには、使用可能なすべての COM ポートが含まれますが、
                これに限定されるわけではありません。
・BaudRate    :シリアル ボー レートを取得または設定します。
・BytesToRead :受信バッファー内のデータのバイト数を取得します。
・BytesToWrite:送信バッファー内のデータのバイト数を取得します。
・CtsHolding  :Clear To Send ラインの状態を取得します。
・DsrHolding  :DSR (Data Set Ready) シグナルの状態を取得します。
・IsOpen      :SerialPort オブジェクトの開いている状態または
                閉じた状態を示す値を取得します。
・Parity      :パリティ チェック プロトコルを取得または設定します。
・DtrEnable   :シリアル通信中に、DTR (Data Terminal Ready)シグナルを
                有効にする値を取得または設定します。
・DataBits    :バイトごとのデータ ビットの標準の長さを取得または設定します。
・StopBits    :バイトごとのストップ ビットの標準の数を取得または設定します。
・ReadBufferSize:SerialPortの入力バッファーのサイズを取得または設定します。
・ReadTimeout :読み取り操作が完了していないときに、
                タイムアウトになるまでのミリ秒数を取得または設定します。
<メソッド>
・Close()     :ポート接続を閉じ、IsOpenプロパティを false に設定し、
                内部 Stream オブジェクトを破棄します。
・Open()      :新しいシリアル ポート接続を開きます。
・Read(Byte(), Int32, Int32):
                SerialPort の入力バッファーから複数のバイトを読み取り、
                読み取ったバイトを指定したオフセットでバイト配列に書き込みます。
・ReadByte()  :SerialPort の入力バッファーから、同期で 1 バイトを読み取ります。
・Write(Byte(), Int32, Int32):
                バッファーのデータを使用して、指定したバイト数をシリアル ポートに書き込みます。
<イベント>
・DataReceived:SerialPort オブジェクトによって表される
                ポートを介してデータが受信されたことを示します。



今回のプログラムをテストするためには外部装置か、もう一台別のPCが必要になりますが、 そんなことをしなくてもデバッグができるソフト(ドライバ)が在ります。

com0com というドライバで、PC上に仮想シリアルポートを2個作成し、 その2個をループバックできる様に仮想的に接続できるという優れものです。 以下のリンク先でソフトをダウンロードしてインストールしてみて下さい。 (尚、もう一台のPCなどがあれば必要ありませんが)

http://sourceforge.net/projects/com0com/

このドライバをインストールすると、私のPCではCOM7COM8が追加で生成されました。
インストール後のPCの状況を以下の図に示します。


COM7側をテスト用送信プログラムとするのですが、 通信テスト用に以下のフリーソフトを使いました。
「のん」さんといわれる方が作成された「RS232Cテストツール」です。
以下のサイトにアクセスすれば、ダウンロードできます。

http://nonsoft.la.coocan.jp/Download/Rs232cTool/index.html

この方はいろいろなフリーソフトを作成されている様です。使えるソフトが満載です。

インストール後の「RS232Cテストツール」を動作させている様子を以下に示します。


では実際のプログラムを以下に示しますので、説明します。

フォームにSerialPortTextBoxButtonを各1個ずつ貼り付けます。
フォームロードイベントでは、シリアルポートの設定を行い、ポートのオープン処理を行います。 ポートの設定は、ポート名「COM8」、通信速度「9600BPS」、パリティ「無し」、データビット数「8」、 ストップビット「1Bit」です。

SerialPortの受信イベントにより、受信バッファー内のデータのバイト数分のバイト配列を宣言し SerialPortReadコマンドで受信バイトを全て読込みます。
読込んだバイト配列を文字列に変換し、TextBoxに設定します。

プログラム的には出来ている様な感じがしますが、これをデバッグモードで実行してみます。

SerialPortコントロールの使い方(最初)

Public Class frmSerial

    ''' 
    ''' フォームロードイベント
    ''' 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        With SerialPort1
            'シリアルポートの設定  
            .PortName = "COM8"                  'ポート名  
            .BaudRate = 9600                    '通信速度指定  
            .Parity = IO.Ports.Parity.None      'パリティ指定  
            .DataBits = 8                       'ビット数指定  
            .StopBits = IO.Ports.StopBits.One   'ストップビット指定  
            'シリアルポートのオープン  
            .Open()
        End With
    End Sub

    ''' 
    ''' フォームクローズイベント
    ''' 
    Private Sub Form1_FormClosed(ByVal sender As Object, 
                                 ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        'シリアルポートのクローズ  
        SerialPort1.Close()
    End Sub

    ''' 
    ''' シリアルポート受信イベント  
    ''' 
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, 
                                         ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
                                         Handles SerialPort1.DataReceived
        'データ受信  
        Dim arrByte As Byte() = New Byte(SerialPort1.BytesToRead - 1) {} '受信バッファー内のデータのバイト数分  
        'SerialPort の入力バッファーからバイト数を読み取り  
        SerialPort1.Read(arrByte, 0, arrByte.GetLength(0))
        '受信バイト配列を文字列変換  
        Dim str As String = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(arrByte)
        'テキストBOXに文字列表示関数  
        DisplayText(str)
    End Sub

    ''' 
    ''' テキストBOXに文字列表示関数
    ''' 
    ''' <param name="strDisp">表示文字列</param>
    Private Sub DisplayText(ByVal strDisp As String)
        'テキストBOXに文字列を追加  
        Me.TextBox1.Text &= strDisp
    End Sub

    ''' 
    ''' [Clear]ボタン処理
    ''' 
    Private Sub btnClear_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnClear.Click
        Me.TextBox1.Text = ""
    End Sub

End Class

このプログラムをデバッグモードで実行させて待機状態にして置き、 先ほどの「RS232Cテストツール」を実行し、送信TEXTにデータを設定し、送信します。 送信ボタン押下した時に、今回のプログラムのTextBoxにデータが表示されるはずですが 実際は以下の様なエラーが発生しました。

スレッド間のアクセスが起きてエラーが発生した様です。
そこで調べたところ、MSDNの説明によれば、
DataReceived イベントは、データが SerialPort オブジェクトから受信されたときにセカンダリ スレッドで発生します。 メインの Form または Control で要素を変更する必要がある場合は、 Invoke を使用して変更要求をポストバックします。これにより、適切なスレッドで処理が実行されるようになります。
とあります。結局、DataReceivedイベントは別スレッドなので、フォームのコントロールなどにアクセスする場合は Invoke等を使用しなさいとのことの様です。

プログラムを以下の様に書き換えました。

SerialPortコントロールの使い方(正常処理)

Public Class frmSerial

    ''' 
    ''' フォームロードイベント
    ''' 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        With SerialPort1
            'シリアルポートの設定  
            .PortName = "COM8"                  'ポート名  
            .BaudRate = 9600                    '通信速度指定  
            .Parity = IO.Ports.Parity.None      'パリティ指定  
            .DataBits = 8                       'ビット数指定  
            .StopBits = IO.Ports.StopBits.One   'ストップビット指定  
            'シリアルポートのオープン  
            .Open()
        End With
    End Sub

    ''' 
    ''' フォームクローズイベント
    ''' 
    Private Sub Form1_FormClosed(ByVal sender As Object, 
                                 ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        'シリアルポートのクローズ  
        SerialPort1.Close()
    End Sub

    ''' 
    ''' シリアルポート受信イベント  
    ''' 
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, 
                                         ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
                                         Handles SerialPort1.DataReceived
        'データ受信  
        Dim arrByte As Byte() = New Byte(SerialPort1.BytesToRead - 1) {} '受信バッファー内のデータのバイト数分  
        'SerialPort の入力バッファーからバイト数を読み取り  
        SerialPort1.Read(arrByte, 0, arrByte.GetLength(0))
        'デリゲート生成  
        Dim dlg As New DisplayTextDelegate(AddressOf DisplayText)
        '受信バイト配列を文字列変換  
        Dim str As String = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(arrByte)
        'デリゲート関数をコールする  
        Me.Invoke(dlg, New Object() {str})
    End Sub

    'Invokeメソッドで使用するデリゲート宣言  
    Delegate Sub DisplayTextDelegate(ByVal strDisp As String)

    ''' 
    ''' テキストBOXに文字列表示関数
    ''' 
    ''' <param name="strDisp">表示文字列</param>
    Private Sub DisplayText(ByVal strDisp As String)
        'テキストBOXに文字列を追加  
        Me.TextBox1.Text &= strDisp
    End Sub

    ''' 
    ''' [Clear]ボタン処理
    ''' 
    Private Sub btnClear_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnClear.Click
        Me.TextBox1.Text = ""
    End Sub

End Class

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コントロールの使い方その2
SerialPortコントロールの使い方その3(外部装置からの垂れ流しデータ受信)
SerialPortコントロールの使い方その4(データ受信時にイベントを発生させる)
SerialPortコントロールの使い方その5(データ受信時及び、信号変化時にイベントを発生させる)
SerialPortコントロールの使い方その6(ハンドシェィクによるデータ送受信)

おすすめ本

PR

コメント

コメントを書く