RS232C シリアル通信                   

  ・文字の送受信 


■ 文字の送受信(PC-PIC間) 

 C#のコンポーネントの中に.NET Framework 2.0からシリアル通信用のコンポーネントが追加されました。以下にこの通信コンポーネントを使った通信の例を紹介します。

  <試作品仕様>
  ・ PCのCOMポートとPICをつなぎ  PC(Microsoft .NET Framework 3.0)とPIC間の通信をおこなう。
    送受信は1バイトのASCIIコードとする。(16バイトのUnicodeではない)
  ・ PCの画面上の”A”、”B”、”C”ボタンをマウスでクリックすると A、B、C が送信される。
  ・ PIC側でこれを受信し、液晶にそれぞれ以下のように表示する。
      (例)  2番目にクリックしたボタンが”B”の場合 ……  buf[1]=B
  ・ ”Enter”ボタンをボタンをクリックすると ”\r”が送信され、それまでに送信されてきた文字すべてをまとめて1行で 液晶に表示する。
    (例)  ”A” ”B” ”C”  とクリックしたあとに”Enter”がクリックされた場合  …… ABC

  ・また ”Enter”ボタンがクリックされた時にはそれまでに送信されてきた文字をまとめてPC側に送信する。
  ・PC側ではおくられてきた文字をテキストボックスに表示する

下記については PIC側送受信を参照願います
<試作品回路図><試作品外観><PIC側プログラム><動作結果>

<プログラム> <動作結果>
        public byte[] SendData = new byte[10];
        string strReceive;
 
        public Form1()
        {
            InitializeComponent();
            serialPort1.PortName = "COM4";  //COM4 ポート使用
            serialPort1.BaudRate = 9600;   //通信速度 9600bps
            serialPort1.Parity = System.IO.Ports.Parity.None;  //パリティなし
            serialPort1.DataBits = 8;  //データ長 8ビット
            serialPort1.StopBits = System.IO.Ports.StopBits.One;   //ストップビット 1
            serialPort1.NewLine = "\r\n";//ReadLine(),WriteLine()が末尾と判断する値の設定
                                            //\r\n:defalut Windows     \n: Unix
            serialPort1.Open();
            serialPort1.DtrEnable = true;  //DTR(Data Terminal Ready) データ端末レディ
            serialPort1.RtsEnable = true;  //RTS(Request To Send) 送信要求

            serialPort1.ReadTimeout = 500;     //500mse 読み込みタイムアウト時間
            serialPort1.WriteTimeout = 500;    //500msec書き込みタイムアウト時間

            SendData[0] = (byte)('A');  // または  SendData[0] = 0x41;
            SendData[1] = 0x42;         // または  SendData[1] = (byte)('B');       
            SendData[2] = (byte)('C');  // または   SendData[2] = 0x43;
        }

        private void buttonA_Click(object sender, EventArgs e)//ボタンA
        {
            serialPort1.Write(SendData, 0, 1);  //COMポートより1バイト送信 オフセット=0
            strReceive = serialPort1.ReadLine();
            textBox1.Text = strReceive;
        }  
        private void buttonB_Click(object sender, EventArgs e)//ボタンB
        {
            serialPort1.Write(SendData,1, 1); //COMポートより1バイト送信 オフセット=1
            strReceive = serialPort1.ReadLine();
            textBox1.Text = strReceive;
         }
        private void buttonC_Click(object sender, EventArgs e)//ボタンC
        {
            serialPort1.Write(SendData, 2, 1); //COMポートより1バイト送信 オフセット=2
            strReceive = serialPort1.ReadLine();
            textBox1.Text = strReceive;
        }
        private void button_Enter_Click(object sender, EventArgs e)//Enterボタン
        {
            byte[] EnteData = new byte[10];
            EnteData[0] = (byte)('\r');

            serialPort1.Write(EnteData, 0, 1);
            strReceive = serialPort1.ReadLine();
            textBox1.Text = strReceive;

            serialPort1.DiscardInBuffer(); //入力バッファークリア
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            serialPort1.Close();
        }

 






ボタン”A"を
クリックした場合












ボタン”A”、”B”、”C”、
”C”、”B”、”A”を
クリック後”Enter”を
クリックした場合

<備考>
1. charはC#では2バイトある。 1バイトのASCIIコードで送受信する場合は byteを使用する。
  通信の送受信に際してはキャスト(byte)を有効に使用する。

2. C#のデータ型のサイズは以下である。

型の形式 型名 サイズ 値の範囲 備考
符号あり
整数
sbyte 8ビット -128〜127 sはsignedの略である
short 16ビット -32768〜32767  
int 32ビット -2147483648〜2147483647  
long 64ビット -9223372036854775808〜9223372036854775807  
符号なし
整数
byte 8ビット 0〜255  
ushort 16ビット 0〜65535 uはunsignedの略である
uint 32ビット 0〜4294967295  
ulong 64ビット 0〜18446744073709551615   
小数点数 float 32ビット 約±1.5×10の-45乗〜±3.4×10の38乗(有効桁7)  
double 64ビット 約±5.0×10の-324乗〜±1.7×10の308乗(有効桁15〜16)  
decimal 128ビット 約±1.0×10の-28乗〜±7.9×10の28乗(有効桁28〜29)  
真理値 bool 8ビット true または flase  
文字 char 16ビット 0〜65535  

3. 配列宣言のフォーマットがC#とC,C++では異なる。
   C#    :  char [ ] data = new char [20];
   C、C++ :   char data[20];

4. SerialPortコンポーネント( →MSDN参照 )
4.1 送信メソッド
   publicvoid WriteLine ( string text) ;
   publicvoid Write ( string text);
   publicvoid Write ( byte [] buffer, uint offset, uint count);
   publicvoid Write ( char [] buffer, uint offset, uint count);
  パラメータ
   text: 出力用の文字列
   buffer:ポートに書き込むデータを格納したバイト配列。
   offset:書き込みを開始するバッファ配列内のオフセット
   count:書き込むバイト数

4.2 受信メソッド
  publicstring ReadLine () ;
   publicint Read ( byte[] buffer, int offset, int count ) ;
   publicint Read ( char[] buffer, int offset, int count ) ;
  パラメータ
   buffer:入力の書き込み先となる文字配列。
   offset:書き込みを開始するバッファ配列内のオフセット。
   count:読み取る文字の数。

■ 文字列の送受信(PC-PIC間) PIC18F4550編
  RS232Cによる送受信を理解するには、デリゲート、マルチスレッド、文字コード等に関する若干の知識が必要となります。
 以下に例を紹介します。PICと通信を行った例でPIC側はPIC側回路&ソフトを参照願います

 <試作品の仕様> 
 ・パソコン側は.NETのC#とし、RS232Cシリアル通信を用いPIC18F4550と文字列の送受信をおこなう。
 ・PIC側のコンボボックスにあらかじめ下記の文字をセットしておきボタンをクリックすると選択されていた文字列を送信する。
  送信される文字の最後尾には’¥r’付加する。
  PIC側ではこれらの文字列を受信したら所定の文字列をPC側に返信する。

     Oda      → Nobunaga
     Toyotomi  → Hideyoshi
     Tokugawa  → Ieyasu
     Tanaka    → Pardon?
 ・ PIC側では受信文字、送信文字を液晶に表示する。
 ・ PC側でも受信文字をテキストボックスに表示する。

<プログラム>

          

   


 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
          //  serialPort1.
            serialPort1.PortName = "COM4";  //COM4 ポート使用
            serialPort1.BaudRate = 9600;   //9600bps
            serialPort1.Parity = System.IO.Ports.Parity.None;  //パリティなし
            serialPort1.DataBits = 8;  //データ長 8ビット
            serialPort1.StopBits = System.IO.Ports.StopBits.One;   //ストップビット 1
            serialPort1.NewLine = "\r\n";//ReadLine(),WriteLine()が末尾と判断する値の設定
            //\r\n:defalut Windows     \n: Unix
            serialPort1.Open();
            serialPort1.DtrEnable = true;  //DTR(Data Terminal Ready) データ端末レディ
            serialPort1.RtsEnable = true;  //RTS(Request To Send) 送信要求

            serialPort1.ReadTimeout = 500;     //500mse 読み込みタイムアウト時間
            serialPort1.WriteTimeout = 500;    //500msec書き込みタイムアウト時間
            comboBox1.SelectedIndex = 0;        //コンボボックス選択値の初期値設定   

        }

        delegate void ReceiveDagete(string str); //string型の引数を持つデリゲートを宣言する。

        private void SetText(string str)
        {
            ReceiveTextBox.Text = str;
        }

       
        Encoding encSjis = Encoding.GetEncoding("shift-jis");   //シフトJISのエンコードクラスを宣言
        Encoding encUni = Encoding.GetEncoding("unicode");  //ユニコード(UCS-16)のエンコードクラスを宣言

        private void button1_Click(object sender, EventArgs e)
        {
            string strSend = comboBox1.Text;    //
            strSend += '\r';    //終端に\r追加
            Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をunicode→Shift-jisに変換してをByte配列に格納
            serialPort1.Write(byteArry, 0, byteArry.Length); //送信
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            serialPort1.Close();//シリアルポートクローズ
        }

        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); //配列をunicodeの文字列に変換

            ReceiveDagete receiveDelegete = new ReceiveDagete(SetText); //デリゲートのインスタンス生成
            this.Invoke(receiveDelegete, strUni);   //セカンドスレッドからメインスレッドのinvoke経由で書き込み

        }

    

    }



  
動作結果


■ 文字列の送受信(PC-PC間)

   1台のパソコンのCOM3ポートとCOM4ポート間をクロスケーブル(自作:下記写真参照)で接続した送受信の結果を以下に紹介します。

<試作品の仕様>
  ・1台のパソコンのCOMポート間のRS232C通信による漢字の送受信をおこなう
  ・COMポート間の通信における文字コードはシフトJISとする。
  ・コンボボックスに設定した以下の文字列(左側)に対し文字列(右側)を返信させる。
       文字列(左側)           (文字列右側)
     古池や 蛙飛び込む   →       水の音
     五月雨を 集めて早し  →       最上川
     Hellow World        →       Paredon ?


プログラム
   

public partial class Form1 : Form { string Furuike = "古池や 蛙飛び込む"; string Samidare = "五月雨を 集めて"; string Hellow = "Hellow Wolrd"; string MizunoOto = "水の音"; string Mogamigawa = "最上川"; string Pardon = "Pardon ?"; string strUniA; //COM4ポートのCOM3ポートへの送信文字列 //文字を変換するクラスを宣言 Encoding encSjis = Encoding.GetEncoding("shift-jis"); //Encoding encUTF8 = Encoding.GetEncoding("utf-8"); Encoding encUni = Encoding.GetEncoding("unicode"); public Form1() { InitializeComponent(); comboBox1.Items.Clear();//コンボボックスクリア comboBox1.Items.Add(Furuike); //Item 0 = "古池や 蛙飛び込む" comboBox1.Items.Add(Samidare); //Item 1 = "五月雨を 集めて早し" comboBox1.Items.Add(Hellow); //Item 2 = "Hellow World" comboBox1.SelectedIndex = 0; //コンボボックス選択値の初期値設定 } delegate void ReceiveDelegate(string str); //デリゲートプロトタイプ宣言 private void SetText_Q(string str) { Com4ReceiveTextBox.Text = str; } private void SetText_A(string str) { Com4SendTextBox.Text = str; } private void SetText_Z(string str) { Com3ReceiveTextBox.Text = str; } private void button1_Click(object sender, EventArgs e) { if (serialPort1.IsOpen == false) serialPort1.Open(); //シリアルCOM3ポートオープン if (serialPort2.IsOpen == false) serialPort2.Open(); //シリアルCOM4ポートオープン string strSend = comboBox1.Text; Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をShift-jisに変換してをByte配列に格納 serialPort1.Write(byteArry, 0, byteArry.Length); //送信 } private void serialPort2_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[serialPort2.BytesToRead]; //受信文字 serialPort2.Read(byteRead, 0, serialPort2.BytesToRead);//読み込み //shift-jis からunicodeに変換する byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); string strUniQ = encUni.GetString(byteUni); ReceiveDelegate receiveDelegate_Q = new ReceiveDelegate(SetText_Q); this.Invoke(receiveDelegate_Q, strUniQ); if (strUniQ == Furuike) strUniA = MizunoOto; else if (strUniQ == Samidare) strUniA = Mogamigawa; else strUniA = Pardon; ReceiveDelegate receiveDelegate_A = new ReceiveDelegate(SetText_A); this.Invoke(receiveDelegate_A, strUniA); Byte[] byteArry = encSjis.GetBytes(strUniA); //'送信文字をShift-jisに変換してをByte配列に格納 serialPort2.Write(byteArry, 0, byteArry.Length); //送信 } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { serialPort1.Close(); serialPort2.Close(); } private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[serialPort1.BytesToRead]; //受信文字 serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//読み込み //shift-jis からunicodeに変換する byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); string strUni = encUni.GetString(byteUni); ReceiveDelegate receiveDelegate_Z = new ReceiveDelegate(SetText_Z); this.Invoke(receiveDelegate_Z, strUni); } }
<実行結果>

■ 漢字文字列の送受信(PC−PIC間)
  PCとPIC(PIC18F4550)間でのシフトJISによる漢字の送受信の例を紹介します。

<試作品の仕様>     → PIC側ソフト、ハード
・パソコン側は.NETのC#とし、RS232Cシリアル通信を用いPIC18F4550と文字列の送受信をおこなう。
 ・PC側のコンボボックスにあらかじめ下記の文字をセットしておく。送信ボタンをクリックして選択されていた文字列を送信する。
  送信される文字の最後尾には’¥r’付加する。
  PIC側ではこれらの文字列を受信したら、以下に定めた文字列をPC側に返信する。

     織田(織:0x9044 田:0x9363)      → 0x904D(信)  0x92B7(長)
     豊臣(豊:0x964C 臣:0x9062)     → 0x8F47(秀)  0x8B67(吉)
     徳川(徳:0x93BF 川:0x90EC)     → 0x89C6(家)  0x8D4E(康)
     田中      → Pardon?
 ・ PIC側では受信文字を16進数表示で受信文字 及び送信文字を液晶に表示する。
 ・ PC側では、受信文字を漢字でテキストボックスに表示する。

プログラム
 public partial class Form1 : Form
    {

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

        
        public Form1()
        {
            InitializeComponent();
            serialPort1.PortName = "COM4";  //COM4 ポート使用
            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("織田");
            comboBox1.Items.Add("豊臣");
            comboBox1.Items.Add("徳川");
            comboBox1.Items.Add("田中");
            comboBox1.SelectedIndex = 0;

        }
        delegate void ReceiveDelegate(string str);//デリゲート宣言

        private void SetText(string str)
        {
            textBox1.Text = 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);
        }
    } 

  

<実行結果>

 送受信文字 
(シフトJIS)
PC側 PIC側
(上段:受信データ  下段:送信データ)
織田信長

織:0x9044
田:0x9363
信:0x904D
長:0x92B7
豊臣秀吉

豊:0x964C
臣:0x9062
秀:0x8F47
吉:0x8B67
徳川家康

徳:0x93BF
川:0x90EC
家:0x89C6
康:0x8D4E

(注) 液晶表示で1、2バイト目と3、4バイト目の間に1文字分の空白がありますが、これは液晶表示する際漢字(2バイト)データをわかりやすく
    するために表示制御で挿入した空白です。実際の送受信においては、4バイトデータの中間に空白データ(0x00など)はありません