3章:Windows用シリアルモニタ_プログラム

    作成2015.08.13

  1. Windows用シリアルモニタ_ソースプログラム
     Arduino IDEでは、シリアルモニタ機能があり、USBデータ送信とUSBデータ受信内容の確認が可能ですが、 Windows側で受信データの変換処理等を行うには、自作のシリアルモニタ_プログラムが必要となります。

     まずは下記の「47-3.zip」ファイルをダウンロードしてください。
    [47-3.zip]をダウンロードする。

    解凍するとフォルダー内にPC Basic Communicationフォルダーがあります。PC Basic Communicationフォルダー内に
    (1)Microsoft Visual C#2012フォルダー
    *Basic Communicationフォルダー:ソースファイル群
    *Csharp Simple CDC Demo.exe:実行ファイル

    (2)Microsoft Visual Basic 2010 Expressフォルダー
    *Basic Communicationフォルダー:ソースファイル群
    *VB.net 2005 Simple CDC Demo.exe:実行ファイル

    (3)注意事項
    *Microsoft Visual C# 2012 Express(ソース)はVS Express for Desktopを管理者として実行する必要があります。 (ダブルクリック起動ではビルドが成功しません。)


  2. Csharp Simple CDC Demo.exeの実行
    (1)Basics/Analog Read Voltageの回路図条件とします。
    (2)Basics/Analog Read Voltageのスケッチを書込み済みとします。
    (3)パソコンにUSB接続します。
    (4)Csharp Simple CDC Demo.exeをダブルクリックで起動します。
    (5)COM10を選択し、Connectボタンを押します。
    (6)可変抵抗で電圧を変化させます。
    (7)Closeボタンを押して、停止させます。
    (8)以下の画面となります。



    *テキストボックス内のデータは選択してコピーできます。


  3. Microsoft Visual C#2012のソースコード
     Windows Forms ControlsをThread-Safe Callsする方法については以下のアドレスを参照する必要があります。
    https://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx

     以下にMicrosoft Visual C#2012のソースコードを示します。
    //Here are some useful articles when creating new PC applications for COM ports:
    //(links valid as of June 3, 2008)
    //
    //"SerialPort Class"
    //http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx
    //
    //"SerialPort Members"
    //http://msdn.microsoft.com/en-us/library/system.io.ports.serialport_members.aspx
    //
    //"SerialPort.DataReceived Event"
    //http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx
    //
    //"How to: Make Thread-Safe Calls to Windows Forms Controls"
    //http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx
    //
    //"The C# Language"
    //http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx
    //
    //"C# Tutorials"
    //http://msdn.microsoft.com/en-us/library/aa288436.aspxusing System;
    
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO.Ports;
    
    namespace Csharp_Simple_CDC_Demo
    {
        public partial class Form1 : Form
        {
            //txtDataReceivedテキストボックスに文字列を書き込むスレッドのためのデリゲート関数を作成します
            delegate void SetTextCallback(string text);
    
            //Form1クラスのコンストラクタ。この関数が作成されフォームオブジェクトのすべてを初期化します。
            public Form1()
            {
                InitializeComponent();
                //Initialize the COM ports list
                UpdateCOMPortList();
            }
    
            //定期的に起動され、COMポートのリストボックスを更新します。
            private void UpdateCOMPortList()
            {
                int i;
                bool foundDifference;
    
                i = 0;
                foundDifference = false;
    
                //If the number of COM ports is different than the last time we
                //  checked, then we know that the COM ports have changed and we
                //  don't need to verify each entry.
                if (lstCOMPorts.Items.Count == SerialPort.GetPortNames().Length)
                {
                    //Search the entire SerialPort object.  Look at COM port name
                    //  returned and see if it already exists in the list.
                    foreach (string s in SerialPort.GetPortNames())
                    {
                        //If any of the names have changed then we need to update 
                        //  the list
                        if (lstCOMPorts.Items[i++].Equals(s) == false)
                        {
                            foundDifference = true;
                        }
                    }
                }
                else
                {
                    foundDifference = true;
                }
    
                //If nothing has changed, exit the function.
                if (foundDifference == false)
                {
                    return;
                }
    
                //If something has changed, then clear the list
                lstCOMPorts.Items.Clear();
    
                //Add all of the current COM ports to the list
                foreach (string s in SerialPort.GetPortNames())
                {
                    lstCOMPorts.Items.Add(s);
                }
                //Set the listbox to point to the first entry in the list
                lstCOMPorts.SelectedIndex = 0;
            }
    
            //Timer1のIntervalに設定した数値のms毎に実行されます。
            private void timer1_Tick(object sender, System.EventArgs e)
            {
                //Update the COM ports list so that we can detect
                //  new COM ports that have been added.
                UpdateCOMPortList();
            }
    
    
            //Connectボタンが推されると実行されます。
            private void btnConnect_Click(object sender, System.EventArgs e)
            {
                try
                {
                    //Get the port name from the application list box.
                    //  the PortName attribute is a string name of the COM port (e.g. - "COM1").
                    serialPort1.PortName = lstCOMPorts.Items[lstCOMPorts.SelectedIndex].ToString();
    
                    //Open the COM port.
                    serialPort1.Open();
    
                    //Change the state of the application objects
                    btnConnect.Enabled = false;
                    lstCOMPorts.Enabled = false;
                    btnClose.Enabled = true;
    
                    //Clear the textbox and print that we are connected.
                    txtDataReceived.Clear();
                    txtDataReceived.AppendText("Connected.\r\n");
                }
                catch
                {
                    //If there was an exception, then close the handle to 
                    //  the device and assume that the device was removed
                    btnClose_Click(this, null);
                }
            }
    
            //Closeボタンが押されると実行されます。
            private void btnClose_Click(object sender, System.EventArgs e)
            {
                //Reset the state of the application objects
                btnClose.Enabled = false;
                btnConnect.Enabled = true;
                lstCOMPorts.Enabled = true;
    
                try
                {
                    //Dispose the In and Out buffers;
                    serialPort1.DiscardInBuffer();
                    serialPort1.DiscardOutBuffer();
    
                    //Close the COM port
                    serialPort1.Close();
                }
                //If there was an exeception then there isn't much we can do.  The port is no longer available.
                catch { }
            }
    
            //データがCOMポートで受信されると、この関数が呼び出されtxtDataReceivedテキストボックスにそのデータを書き込みます
            private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                try
                {
                    // ReadExisting()関数は、COMポートのバッファに現在利用可能なすべてのデータを読み込みます。
                    //この例では、setText()関数に使用可能なCOMポートのすべてのデータを送信しています。
                    //注:_DataReceived()関数は、アプリケーションの他の部分から独立したスレッドで起動されます。
                    //デリゲート機能が,、正しく他のスレッドの内部の管理対象オブジェクトにアクセスするために必要です。
                    //管理対象オブジェクトをてtextBoxに書くことになりますので、デリゲート機能が要求されます。
                    //デリゲートの機能とその使用方法の詳細については、のsetText()関数を参照してください。
                    SetText(serialPort1.ReadExisting());
                }
                catch
                {
                    //If there was an exception, then close the handle to the device and assume that the device was removed
                    btnClose_Click(this, null);
                }
            }
    
            //この関数は、txtDataReceivedテキストボックスに入力されたテキストを出力します。
            //呼び出し元のスレッドがテキストボックスを所有するスレッドと同じである場合、appendText()メソッドを直接呼び出されます。
            //メインスレッド以外がこの関数を呼び出した場合は、メインスレッドで再び実行されるように、デリゲート関数のインスタンスが作成されます。
            private void SetText(string text)
            {
                //InvokeRequiredは呼び出し元のスレッドIDと作成スレッドIDの比較のため必要です。
                //これらのスレッドが異なっている場合は、trueを返します。
                //テキストボックスにテキストを直接追加できるか、デリゲート関数のインスタンスを起動する必要があるかをこの属性を利用します。
                if (txtDataReceived.InvokeRequired)
                {
                    //deleage機能を起動する必要があります。
                    //SetTextCallbackデリゲートのインスタンスを作成し、デリゲートの機能を割り当てます。
                    //これは事実上、第二のスレッドの代わりに、同じsetText()関数が、メインスレッド内で呼び出されます。
                    SetTextCallback d = new SetTextCallback(SetText);
    
                    //他のスレッドからこの関数に渡されたテキストを送信する新しいデリゲートを呼び出します
                    Invoke(d, new object[] { text });
                }
                else
                {
                    //If this function was called from the same thread that 
                    //  holds the required objects then just add the text.
                    txtDataReceived.AppendText(text);
                }
            }
    
            //SendDataボタンが押されたときに実行されます。
            private void btnSendData_Click(object sender, System.EventArgs e)
            {
                try
                {
                    //Write the data in the text box to the open serial port
                    serialPort1.Write(txtData.Text);
                }
                catch
                {
                    //If there was an exception, then close the handle to 
                    //  the device and assume that the device was removed
                    btnClose_Click(this, null);
                }
            }
        }
    }
    


  4. Windows用シリアルモニタアプリまとめ
    (1)Windowsでは、Windows Forms Controlsであるテキストボックスを扱うスレッドとシリアル受信のスレッドがことなるため、ソースコードが難解となります。
    (2)言語としてはC#か、VBが扱いやすいです。
    (3)Arduino IDEのスケッチとC#は記述の類似点が多く、混乱をさけるためにはC#が良いと思います。
    (4)Windows用のシリアルモニタ機能プログラムは難解なのですが、Windows側で受信データの変換処理が可能となります。




4章:Arduino(アルドゥイーノ)演習(Digital-01編)に行く。

トップページに戻る。