USB通信 (VC#)                          

  



■ PIC18 CDCクラスMicrochip社デモソフト 

  PICとUSB通信を行なう場合、マイクロチップ社から提供(公開)されているいるUSBフレームワークのCDCクラスを使うとPC側のソフトは
 RS232Cの送受信のようにあつかうことができます。このサンプルソフトがマイクロチップ社のHPに公開されています。以下のプログラムは 
 マイクロチップ社のMCHPFSUSB Framework 2.3をダウンロードして解凍後PCにできる …\Microchip Solutions\
 USB Device - CDC - Basic Demo\PC Software ExampleVCsharp 2005フォルダに収納されているC#のサンプルプログラムです。この
 ソフトは マイクロチップ  DemoBoard(PICDEM FS USB DM163025)($59.99ドル)用デモソフトのPC側ソフトです。 コメント行は翻訳、
 、削除、追記等をしていますが 、ソースコードの変更は行なっていません。 全体のハード 及びPIC側のソフトは 全体&PIC側を参照
 願います

       <プログラム>
  
        
        delegate void SetTextCallback(string text);//デリゲート宣言

      
        public Form1()
        {
            InitializeComponent();

            UpdateCOMPortList();    //使用可能COMポートリスト更新
        }


        private void UpdateCOMPortList()    //使用可能COMポートリスト作成
        {
            int i;
            bool foundDifference;

            i = 0;
            foundDifference = false;

            if (lstCOMPorts.Items.Count == SerialPort.GetPortNames().Length)
            {
                foreach (string s in SerialPort.GetPortNames())
                {
                   
                    if (lstCOMPorts.Items[i++].Equals(s) == false)
                    {
                        foundDifference = true;
                    }
                }
            }
            else
            {
                foundDifference = true;
            }

            if (foundDifference == false)
            {
                return;
            }

            lstCOMPorts.Items.Clear();
            foreach (string s in SerialPort.GetPortNames())
            {
                lstCOMPorts.Items.Add(s);
            }
            lstCOMPorts.SelectedIndex = 0;
        }

        private void timer1_Tick(object sender, System.EventArgs e) //COMポートリストの周期的更新
        {
                UpdateCOMPortList();
        }

        private void btnConnect_Click(object sender, System.EventArgs e)    //選択されたCOMポートをオープンする
        {
         
            try
            {
                serialPort1.PortName = lstCOMPorts.Items[lstCOMPorts.SelectedIndex].ToString();

                serialPort1.Open();  //COMポートオープン

                btnConnect.Enabled = false;
                lstCOMPorts.Enabled = false;
                btnClose.Enabled = true;

                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);
            }
        }

        private void btnClose_Click(object sender, System.EventArgs e)  //COMポートのクローズ
        {
            btnClose.Enabled = false;
            btnConnect.Enabled = true;
            lstCOMPorts.Enabled = true;

            try
            {
                serialPort1.DiscardInBuffer();  //入力バッファーのデータ破棄
                serialPort1.DiscardOutBuffer(); //出力バッファーのデータ破棄

                serialPort1.Close();
            }
            //If there was an exeception then there isn't much we can
            //  do.  The port is no longer available.
            catch { }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) //データ受信
        {
            try
            {
                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);
            }
        }

       
        private void SetText(string text)   //受信スレッドからメインスレッドへの書き出し
        {
            if (txtDataReceived.InvokeRequired)
            {
                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);
            }
        }
        
         private void btnSendData_Click(object sender, System.EventArgs e)  //テキストボックス内のデータをCOMポート経由で送信
        {
            try
            {
                 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);
            }
        }
          

PIC18F4550−PC 間  CDCクラス通信
 ( 自作PICキバン + Microchip社デモソフト)

<動作結果>
    デモソフト:
        Basic Demo

@コンボボックスからCOM8ポートを選択

AConnectボタンをクリック
  
→リッチテキストボックスにConnectedが表示される

BPICキバン上のSWを押すと文字列
 Button Pressed--がUSB送信され、左記ウィンドウの リッチテキストボックスに表示される。

Cテキストボックスに5をキーインて、Send Dataボタンを クリックする。
  →PICキバン側で+1インクリメントされた6がUSB通信で返信され、これが左記リッチテキストボックスに表示される

      ★全体のハード 及びPIC側のソフト
                 → 全体&PIC側参照

    デモソフト:

        Serial Emulator


送信側(USB通信):PICDEMサンプルソフト
受信側(RS232C通信):Tera Term

     

@左記ウィンドウのテキストボックスに文字列
 Hellow World !!をキーインして、Send Dataボタンをクリックする

APIC側キバン(PICDEM相当自作キバン)では、USBケーブル経由送信されてきたたこの文字列を受信した後、この文字列をRS232Cケーブル経由でRS232C通信でエコーバックする

BPC側ではエコーバックされてきたデータを通信ソフトTera Termで受信し、これをウィンドウに表示する。
                      




      ★全体のハード 及びPIC側のソフト
                 → 全体&PIC側参照


(注)ウィンドウの背景にある画像は、本テーマとは関係ありません

    デモソフト:
        Serial Emulator


送信側(RS232C通信):Tera Term
受信側(USB通信):PICDEMサンプルソフト


@Tera Term(注)に Data from TeraTerm とキーイン後、エンターキーを押しRS232C経由でPIC側(PICDEM相当)にデータを送信する。
APIC側では受信データをそのままUSBケーブル経由でPC側に送信する。
BPC側ではPICDEMデモソフトの右記ウィンドウのリッチテキストボックスで受信データを表示する。


      ★全体のハード 及びPIC側のソフト
                 → 全体&PIC側参照

(注)TeraTermのローカルエコーがONであるのでキーインしたデータが表示されている。



■ PIC18 CDCクラス 通信 (液晶付き) 
  マイクロチップ社のMCHPFSUSB Framework 2.3をダウンロードすると入手できる公開ソフトをベースに設計した、PCとPIC18F4550間のUSB通信(CDCクラス 液晶付)の例を紹介します。 ハード 及びPIC側のソフトは こちらを参照願います 
            

<試作品仕様>
 ・PC側からデータをPIC側にUSB CDCクラス通信で送信する。
 ・PIC側では受信した文字列を液晶上段に、受信データに基づき返信したデータを液晶下段に表示する。
 ・PC側でも受信したデータをテキストボックスに表示する。
 ・PC側からの送信データ 及びPIC側からの返信データは以下とする。
     @ How are you ?     →  I am fine !!
     A Your name ?      →  My name is PIC
     B This is a pen      →  Pardon?                 

   <プログラム>


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;      //要追加

namespace USB_LCD_Shift_Jis
{
    public partial class Form1 : Form
    {
        //文字を変換するクラスを宣言
        Encoding encSjis = Encoding.GetEncoding("shift-jis");
        Encoding encUni = Encoding.GetEncoding("unicode");

       delegate void SetTextCallback(string text);//デリゲート宣言
   
    

     
            




        public Form1()
        {
            InitializeComponent();
           
            UpdateCOMPortList();    //使用可能COMポートリストチェック

            SendData_ComboBox.Items.Clear();
            SendData_ComboBox.Items.Add("How are you ?   ");
            SendData_ComboBox.Items.Add("Your name ?     ");
            SendData_ComboBox.Items.Add("This is a pen   ");
            SendData_ComboBox.SelectedIndex = 0;        //コンボボックス選択値の初期値設定 

        }

        private void UpdateCOMPortList()    //使用可能COMポートチェック & リスト作成
        {
            int i;
            bool foundDifference;

            i = 0;
            foundDifference = false;

            if (Port_comboBox.Items.Count == SerialPort.GetPortNames().Length)
            {
                foreach (string s in SerialPort.GetPortNames())
                {

                    if (Port_comboBox.Items[i++].Equals(s) == false)
                    {
                        foundDifference = true;
                    }
                }
            }
            else
            {
                foundDifference = true;
            }

            if (foundDifference == false)
            {
                return;
            }

            Port_comboBox.Items.Clear();
            foreach (string s in SerialPort.GetPortNames())
            {
                Port_comboBox.Items.Add(s);
            }
            Port_comboBox.SelectedIndex = 0;
        }

  

        private void CloseBtn_Click(object sender, EventArgs e)
        {
            CloseBtn.Enabled = false;
            ConnectBtn.Enabled = true;
            Port_comboBox.Enabled = true;

            try
            {
                serialPort1.DiscardInBuffer();  //入力バッファーのデータ破棄
                serialPort1.DiscardOutBuffer(); //出力バッファーのデータ破棄

                serialPort1.Close();
            }
            //If there was an exeception then there isn't much we can
            //  do.  The port is no longer available.
            catch { }

        }

   
        private void timer1_Tick(object sender, EventArgs e)    //COMポートの周期的チェック&更新
        {
            UpdateCOMPortList();
        }

        private void ConnectBtn_Click_1(object sender, EventArgs e)
        {
            try
            {
                serialPort1.PortName = Port_comboBox.Items[Port_comboBox.SelectedIndex].ToString();

                serialPort1.Open();  //COMポートオープン

                ConnectBtn.Enabled = false;
                Port_comboBox.Enabled = false;
                CloseBtn.Enabled = true;

                Receive_textBox.Clear();
                Receive_textBox.AppendText("Connected.\r\n");
            }
            catch   // COMポートが開けない場合
            {
                CloseBtn_Click(this, null);
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)     //受信
        {
            try
            {
                byte[] byteRead = new byte[serialPort1.BytesToRead];  //受信文字

                serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//shift-JIS読み込み
                byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead);   //shift-JIS からunicodeに変換する
                string strUni = encUni.GetString(byteUni);  //配列を文字列に変換

                SetTextCallback SetTextCallback = new SetTextCallback(SetText);
                this.Invoke(SetTextCallback, strUni);


            }
            catch
            {
                //If there was an exception, then close the handle to 
                //  the device and assume that the device was removed
               CloseBtn_Click(this, null);
            }

        }

        private void SetText(string text)   //受信スレッドからメインスレッドへの書き出し
        {
            if (Receive_textBox.InvokeRequired)
            {
                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.
                Receive_textBox.AppendText(text);
            }
        }

        private void SendBtn_Click_1(object sender, EventArgs e)    //送信
        {
            try
            {
                string strSend = SendData_ComboBox.Text;
                if (!strSend.EndsWith("\r")) strSend += "\r";  //改行が無かったら \rを追加する
                serialPort1.Write(strSend);
            }
            catch
            {
                //If there was an exception, then close the handle to 
                //  the device and assume that the device was removed
                CloseBtn_Click(this, null);
            }

        }

    }

       
  
}

<動作結果>
 @ PC側のウィンドウから仮想COM8ポートを選択してを接続ボタンをクリックする。
 A USB接続が完了して受信データテキストボックスに Connected が表示される。
 B 送信データ用コンボボックススから How are you ? を選択して送信ボタンをクリックする。
 C PIC側で受信した受信データ How are you ? が液晶の上段に表示されています。
 D 返信データとして I am fine !! がプログラムで選択され、これを液晶下段に表示されています。また、同時にPC側にも送信されています。
 E この結果、PC側では 受信したデータ I am fine !! を受信データ用テキストボックスに表示しています。
 F 同様に Your name ?  を送信した場合 My name is PIC が返信された場合も表示されています。
 G 同様に This is a pen  を送信した場合 Pardon? が返信された場合も表示されています。
 

PC側 
送受信ウィンドウ
PIC側 液晶画面



■ PIC32MZ - PC間 CDCクラス ASCII文字列の送受信(キャラクタ液晶、Harmony)


PIC32MZ2048ECH144にキャラクタ液晶を接続した HarmonyによるCDCクラスのUSB通信 送受信の例を紹介します。   → PIC側  ソフト
   
  <試作品仕様>
    ・PCとPIC32MZ間で 文字列の送受信をおこなう。
    ・USBのライブラリはHarmonyのCDCクラスをつかうこと
    ・PC側から文字列に対して PIC側からそれぞれに対応した文字列を返信すること
     送受信の文字列は 以下とする
      PCからの送信文字列            PICからの返信文字列
      Japan\r               Tokyo    
      America\r              Washington
      U.K.\r                London
      France\r              Paris
    ・PICにはキャラくタ液晶を接続し 受信文字列と返信文字列を表示すること
    ・PIC側のダイアログのテキストボックスに受信文字列を表示のこと
    ・ 開発環境  PIC側: Harmony ver. 1.03   XC32 ver.1.34  MPLABX ver.2.35  PIC32MZ2048ECH144 revision 5
              PC側: VC# 2012


        プログラム 
   

   

          

   




using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Kanji_PC_PIC { public partial class Form1 : Form { //文字を変換するクラスを宣言 Encoding encSjis = Encoding.GetEncoding("shift-jis"); Encoding encUni = Encoding.GetEncoding("unicode"); public Form1() { InitializeComponent(); serialPort1.PortName = "COM3"; //COM1 ポート使用 serialPort1.BaudRate = 9600; //9600bps serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし serialPort1.DataBits = 8; //データ長 8ビット serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1 serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間 serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間 comboBox1.Items.Clear(); comboBox1.Items.Add("Japan"); comboBox1.Items.Add("America"); comboBox1.Items.Add("U.K."); comboBox1.Items.Add("France"); // comboBox1.Items.Add("I_am_fine"); comboBox1.SelectedIndex = 0; } delegate void ReceiveDelegate(string str);//デリゲート宣言 private void SetText(string str) { richTextBox1.AppendText(str); } private void button1_Click(object sender, EventArgs e) { if(serialPort1.IsOpen == false)serialPort1.Open();//シリアルポートオープン string strSend = comboBox1.Text; if (!strSend.EndsWith("\r")) strSend += "\r"; //改行が無かったら \rを追加する Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をShift-jisに変換してをByte配列に格納 serialPort1.Write(byteArry, 0, byteArry.Length); //送信 } private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[serialPort1.BytesToRead]; //受信文字 serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//読み込み byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); //shift-jis からunicodeに変換する string strUni = encUni.GetString(byteUni); //配列を文字列に変換 ReceiveDelegate receiveDelegate = new ReceiveDelegate(SetText); this.Invoke(receiveDelegate, strUni); } private void button2_Click(object sender, EventArgs e) { richTextBox1.Clear(); } private void button3_Click(object sender, EventArgs e) { serialPort1.Close(); } } }




 <動作結果>

   PIC側液晶画面
上段: 受信文字列
下段: 返信文字列
PC画面 
送信前     
 PCから "Japan\r"を
送信した場合
   
 PCから 以下の順番で
文字列を送信した場合
"Japan\r"
"America\r"
"U.K.\r"
"France\r"


   

PIC32MZ - PC間 (デバイスモード)CDCクラス 
     文字列送受信            (PIC32MZ評価ボード サンプルソフト)

                      (サンプルプログラム(VC#プロジェクトファイル VC# 2017版) → ダウンロード
                      (サンプルプログラム(実行ファイル) → ダウンロード

                                   ★ PIC側のハードとソフトは こちらを参照願います

<仕様>
 ・PCとPIC32MZ間でUSB接続による文字列の送受信をおこなう。
 ・USBのライブラリはHarmonyのCDCクラスをつかうこと
 ・PC側から文字列に対して PIC側からそれぞれに対応した文字列を返信すること
  送受信の文字列は 以下とする

      PCからの送信文字列 PICからの返信文字列
Japan\r Tokyo 
America\r Washington
U.K.\r  London
France\r  Paris
How are you?\ Pardon?

 ・PICのキャラくタ液晶はI2Cインターフェースのキャラクタ液晶とし、以下を表示のこと。
   1行目 …… PCからの受信文字列
   2行目 …… PCへの送信文字列

 ・PC側のアプリケーションは マイクロソフトのVC#で作成のこと。
 ・PCのアプリケーションプログラムの基本動作は、以下とする。
   尚、USBコネクタの脱着を検出し USB接続状態表示(接続完了/未接続 及びランプ表示の灰色/オレンジ色)に反映のこと。

操作/動作 @プログラム立ち上がり後の初期状態
  USB未接続状態、 
A接続ボタンをPC使用可能COMポートを検索し、使用COMポートのコンボボックスにセットする。セレクトされたCOMポートがPIC側とUSB接続できない場合は COMポート変更等を促すメッセージを表示する。 Bコンボボックスから別のCOMポートを選択する。
PC画面
操作/動作 CPIC側と接続できたCOMポートを選択できた場合は準備完了"I am Ready"のメッセージを表示する。 またこれと同時に送信ボタン、送信データ用のコンボボックス、"接続完了"の文字 及びオレンジ色のランプ表示も行う。 D送信データをコンボボックスから選択後、送信ボタンをクリックしてPIC側に送信する。PIC側からの返信データを受信データ用のリッチテキストボックスに表示する。
 尚、表示された受信データはクリアボタンで消去できること。
E停止ボタンをクリックするとUSB接続は遮断されること。 これに伴い使用COMポートは空欄となり、"未接続"の文字が表示されランプ表示は灰色となること。
PC画面




以下、プログラム抜粋

 Form1.cs [デザイン]
 
 Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports; //追加 シリアルポートコンポーネント用


namespace USB_CDC_Str_SendReceive2
{
public partial class Form1 : Form
{
int OK_COM = 0; //COMポート接続完了フラグ
bool LampCOM = false; //COM/USB 接続表示
bool PerformClick = false; //偽クリック発生 //ピクチャーボックス再描画
bool RichTextBoxWritable = false; //リッチテキストボックス書き込み禁止(許可)



//文字を変換するクラスを宣言
Encoding encSjis = Encoding.GetEncoding("shift-jis");
Encoding encUni = Encoding.GetEncoding("unicode");

delegate void ReceiveDelegate(string str);//デリゲート宣言
public Form1()
{
InitializeComponent();

SendDataCBox.Items.Clear();
SendDataCBox.Items.Add("Japan");
SendDataCBox.Items.Add("America");
SendDataCBox.Items.Add("U.K.");
SendDataCBox.Items.Add("France");
SendDataCBox.Items.Add("How are you ?");
SendDataCBox.SelectedIndex = 0;

SendDataBtn.Visible = false;
SendDataCBox.Visible = false;
SendDataLabel.Visible = false;


}

enum WINDOW_MESSAGES : uint
{
WM_DEVICECHANGE = 0x0219,
}

private enum DBT
{
DBT_DEVICEARRIVAL = 0x8000,
DBT_DEVICEQUERYREMOVE = 0x8001,
DBT_DEVICEQUERYREMOVEFAILED = 0x8002,
DBT_DEVICEREMOVEPENDING = 0x8003,
DBT_DEVICEREMOVECOMPLETE = 0x8004,
}

protected override void WndProc(ref Message m)
{

switch ((WINDOW_MESSAGES)m.Msg)
{
case WINDOW_MESSAGES.WM_DEVICECHANGE:
// pnpEvent(this, EventArgs.Empty);

switch ((DBT)m.WParam.ToInt32())
{
case DBT.DBT_DEVICEARRIVAL:
//ドライブが装着された時の処理を書く
LampCOM = true;
ConnectLabel.Text = "接続完了";
PerformClick = true; //クリックによるリッチテキストクリア動作を無効化
ClearBtn.PerformClick(); //イベントを発生させ、Form1_Paint()を実行して描画を行う。
PerformClick = false; //クリックによるリッチテキストクリア動作を有効化
RichTextBoxWritable = true; //リッチテキストボックス書き込み許可
break;
case DBT.DBT_DEVICEREMOVECOMPLETE:
//ドライブが取り外されたされた時の処理を書く
LampCOM = false;
ConnectLabel.Text = "未接続";
RichTextBoxWritable = false; //リッチテキストボックス書き込み禁止
break;
}



break;
}
base.WndProc(ref m);
}


private void Form1_Paint(object sender, PaintEventArgs e) //USB接続/未接続のイメージランプ描画
{
if(LampCOM == false)
{
Graphics g = pictureBox1.CreateGraphics(); //CreateGraphicsメソッドによりGraphicsオブジェクトを取得
g.FillEllipse(Brushes.Gray, 10, 0, 50, 50); //灰色塗りつぶし 基点(10,0) 幅×高さ:50×50
}
else
{
Graphics g = pictureBox1.CreateGraphics(); //CreateGraphicsメソッドによりGraphicsオブジェクトを取得
g.FillEllipse(Brushes.Orange, 10, 0, 50, 50);//橙色塗りつぶし 基点(10,0) 幅×高さ:50×50
}



}

private void SetText(string str)
{
if(RichTextBoxWritable == true) //リッチテキストボックス書き込み許可の場合
{
richTextBox1.AppendText(str); //文字列追加
richTextBox1.AppendText("\n"); //改行

}
}

private void ComPortConnectTry() //COMポート接続チェック
{



try
{
serialPort1.DiscardInBuffer(); //受信バッファのデータクリア

string strSend = "Are you Ready ?";
if (!strSend.EndsWith("\r")) strSend += "\r"; //改行が無かったら \rを追加する
Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をShift-jisに変換してをByte配列に格納
serialPort1.Write(byteArry, 0, byteArry.Length); //送信

string OK_message = "I am Ready\r\n";

string Response = serialPort1.ReadLine(); //返信データ抜き取り
OK_COM = OK_message.CompareTo(Response); //返信データが "I am Ready\r\n"の場合 1 を返す
if (OK_COM == 1)
{
ConnectLabel.Text = "接続完了";
SendDataBtn.Visible = true;
SendDataCBox.Visible = true;
SendDataLabel.Visible = true;

LampCOM = true;
ConnectBtn.Enabled = true;

}
MessageBox.Show(Response);
RichTextBoxWritable = true;

}
catch (Exception ex2)
{
OK_COM = 0;
ConnectLabel.Text = "未接続";
SendDataBtn.Visible = false;
SendDataCBox.Visible = false;
SendDataLabel.Visible = false;

LampCOM = false;
ConnectBtn.Enabled = false;
RichTextBoxWritable = false; //リッチテキストボックス書き込み禁止


if (ex2 is TimeoutException)
{
string TimeoutStr = "1. COMポートをかえてみてください \n2. COMポートコネクタの抜けなど断線がないチェックしてください。";
MessageBox.Show(ex2.Message + "\n" + TimeoutStr);
}
else MessageBox.Show(ex2.Message);
}


}




private void ConnectBtn_Click(object sender, EventArgs e) //接続ボタン
{
if(ConnectBtn.Text == "停止")
{
serialPort1.Close();//シリアルポートオープン
ConnectBtn.Text = "接続";
SendDataBtn.Visible = false;
SendDataCBox.Visible = false;
SendDataLabel.Visible = false;
ConnectLabel.Text = "未接続";
LampCOM = false;
ComCBox.Items.Clear();
ComCBox.Text = "";

return;
}


if (ConnectBtn.Enabled == true) ConnectBtn.Text = "停止";
else ConnectBtn.Text = "接続";



string[] PortList = SerialPort.GetPortNames();

try
{
ComCBox.Items.Clear();

//シリアルポート名をコンボボックスにセット
foreach (string PortName in PortList)
{
ComCBox.Items.Add(PortName);
}
if (ComCBox.Items.Count > 0)
{
ComCBox.SelectedIndex = 0;
}

serialPort1.PortName = ComCBox.SelectedItem.ToString();

// serialPort1.PortName = "COM3"; //COM1 ポート使用
// serialPort1.PortName = "COM4"; //COM1 ポート使用
serialPort1.BaudRate = 9600; //9600bps
serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし
serialPort1.DataBits = 8; //データ長 8ビット
serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1
serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間
serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間

serialPort1.Open();//シリアルポートオープン

}
catch (Exception ex)
{
DialogResult result = MessageBox.Show
(ex.Message + "\n" + "COMポートがひらけません");
}

ComPortConnectTry(); //COMポート接続チェック

}

private void SendDataBtn_Click(object sender, EventArgs e) //データ送信ボタン
{
try
{
if (serialPort1.IsOpen == false) serialPort1.Open();//シリアルポートオープン

serialPort1.DiscardInBuffer(); //受信バッファのデータクリア

string strSend = SendDataCBox.Text;
if (!strSend.EndsWith("\r")) strSend += "\r"; //改行が無かったら \rを追加する
Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をShift-jisに変換してをByte配列に格納
serialPort1.Write(byteArry, 0, byteArry.Length); //送信
}
catch (Exception ex)
{
DialogResult result = MessageBox.Show
(ex.Message + "\n" + "COMポートがひらけません");
}
}

private void ClearBtn_Click(object sender, EventArgs e) //クリアボタン
{
if(PerformClick == false)richTextBox1.Clear(); //マウスでの実際のクリックが発生した場合のみ リッチテキストクリア
}

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{

byte[] byteRead = new byte[serialPort1.BytesToRead]; //受信文字

serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//読み込み
byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); //shift-jis からunicodeに変換する
string strUni = encUni.GetString(byteUni); //配列を文字列に変換
ReceiveDelegate receiveDelegate = new ReceiveDelegate(SetText);
this.Invoke(receiveDelegate, strUni);
}

private void ComCBox_TextChanged(object sender, EventArgs e)
{

if (serialPort1.IsOpen == true)
{
serialPort1.Close();//シリアルポートクローズ

serialPort1.PortName = ComCBox.SelectedItem.ToString();
serialPort1.BaudRate = 9600; //9600bps
serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし
serialPort1.DataBits = 8; //データ長 8ビット
serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1
serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間
serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間

serialPort1.Open();//シリアルポートオープン

ComPortConnectTry(); //COMポート接続チェック
}
}

}
}



<動作結果>(→ 動画:1080pのHD動画を見ることができます。)

操作/動作 PC画面 & PIC32MZ評価ボード 備考
@プログラム立ち上がり後の初期状態
  USB未接続状態
A接続ボタンをPC使用可能COMポートを検索し、使用COMポートのコンボボックスにセットする。セレクトされたCOMポートがPIC側とUSB接続できない場合は COMポート変更等を促すメッセージを表示する。
Bコンボボックスから別のCOMポートを選択する。
CPIC側と接続できたCOMポートを選択できた場合は準備完了"I am Ready"のメッセージを表示する。 またこれと同時に送信ボタン、送信データ用のコンボボックス、"接続完了"の文字 及びオレンジ色のランプ表示も行う。
D送信データをコンボボックスから選択後、送信ボタンをクリックしてPIC側に送信する。PIC側からの返信データを受信データ用のリッチテキストボックスに表示する。
 尚、表示された受信データはクリアボタンで消去できること。
E停止ボタンをクリックするとUSB接続は遮断されること。 これに伴い使用COMポートは空欄となり、"未接続"の文字が表示されランプ表示は灰色となること。

 USBメモリ 抜き差し検出

 すべてのWindowsメッセージがWndProcメソッドでイベントに置き換えられるわけではありません。所要のイベントを検出するには
WndProcメソッドをオーバーライドしてWindowsメッセージで判別します。
  実験の結果 DBT_DEVICEARRIVAL / DBT_DEVICEREMOVECOMPLETEでは USBメモリとマイクロチップのUSB(デバイスモード)
CDCクラスのUSBコネクタ脱着が検出できました。 しかし USB接続のキーボードやマウスの USBコネクタ脱着は検出できませんでした。
USBコネクタの脱着イベントを正確に取得したい場合はWindowsメッセージに係る資料を精読する必要があります。
実行結果
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinPro_ReDraw_PictBox
{
public partial class Form1 : Form
{
bool LED = false;
public Form1()
{
InitializeComponent();
}

enum WINDOW_MESSAGES : uint
{
WM_DEVICECHANGE = 0x0219,
}

private enum DBT
{
DBT_DEVICEARRIVAL = 0x8000,
DBT_DEVICEQUERYREMOVE = 0x8001,
DBT_DEVICEQUERYREMOVEFAILED = 0x8002,
DBT_DEVICEREMOVEPENDING = 0x8003,
DBT_DEVICEREMOVECOMPLETE = 0x8004,
}

protected override void WndProc(ref Message m) //WndProcメソッドのオーバーライド
{
switch ((WINDOW_MESSAGES)m.Msg) //WINDOW_MESSAGESの判別
{
case WINDOW_MESSAGES.WM_DEVICECHANGE:

switch ((DBT)m.WParam.ToInt32())
{
case DBT.DBT_DEVICEARRIVAL: //ドライブが装着された時の処理を書く
LED = true;
button1.PerformClick(); //button1をクリックしなくとも クリックイベントを発生
// → PictureBox1の再描画イベントを発生
break;
case DBT.DBT_DEVICEREMOVECOMPLETE: //ドライブが取り外されたされた時の処理を書く
LED = false;
button1.PerformClick(); //button1をクリックしなくとも クリックイベントを発生
// → PictureBox1の再描画イベントを発生
break;
default:
break;
}
break;
default:
break;
}
base.WndProc(ref m);
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = pictureBox1.CreateGraphics(); //CreateGraphicsメソッドによりGraphicsオブジェクトを取得

if (LED == false)
{
g.FillEllipse(Brushes.Gray, 10, 0, 50, 50); //灰色塗りつぶし 基点(10,0) 幅×高さ:50×50
}
else
{
g.FillEllipse(Brushes.Orange, 10, 0, 50, 50);//橙色塗りつぶし 基点(10,0) 幅×高さ:50×50
}
}
}
}
 

<USBメモリ抜き出し後>
及び<起動後>




<USBメモリ挿入後>