none
シリアルポートからの受信について RRS feed

  • 質問

  • C# 初心者です。よろしくお願い致します。データ受信についての質問です。C#での受信というのは指定したバッファ数を満たした、あるいは受信から指定したタイムアウトが経過したという感じに読み取れます。なので受信を塊りで完了したらバッファを頭から確認していくような処理になるような気がします。マイコンの組み込みのように受信割り込み毎にデータを評価してヘッダーやフッターを確認しながら処理をしたいと思っているのですが何かそれに近い手法、ヒントなどがありますと大変有り難いです。何卒よろしくお願い致します。
    2018年7月31日 3:18

すべての返信

  • 「マイコンの組み込みのように」というのが、1バイト受信ごとに割り込みが発生して、割り込みハンドラ内で1バイトずつ取り出していくという意味なのであれば、DataReceivedイベントが割り込みのように発生するので、そのイベント内で1バイトずつ取り出して評価すればいいです。

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Task.Run(() =>
                {
                    //別スレッドでダミーデータの送信
                    System.Threading.Thread.Sleep(1000);
                    using (System.IO.Ports.SerialPort portSend = new System.IO.Ports.SerialPort("COM8"))
                    {
                        portSend.Open();
                        portSend.Write("ABC" + "\x0002" + "DEF" + "\x0003" + "GHI" + "\x0004" + "JKL");
                        portSend.Close();
                    }
                });
    
    
                using (System.IO.Ports.SerialPort portReceive = new System.IO.Ports.SerialPort("COM9"))
                {
                    //受信があったらイベント(割り込みのようなもの)で呼び出す関数を登録
                    portReceive.DataReceived += portA_DataReceived;
    
                    portReceive.Open();
                    while (!isEOTReceived)
                    {//テストデータがそろうまでループで待機
                        System.Threading.Thread.Sleep(100);
                    }
    
                    Console.WriteLine(System.Text.Encoding.ASCII.GetString(receivedData));
                }
            }
    
    
            const byte STX = 0x02;
            const byte ETX = 0x03;
            const byte EOT = 0x04;
    
            private static List<byte> receiveBuffer = new List<byte>();//一時的に保存しておくバッファ
            private static byte[] receivedData = null;//受信結果をいれるバイト配列
            private static bool isEOTReceived = false;//受信成功したか
    
            /// <summary>受信があった時に呼び出される関数</summary>
            static void portA_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                System.IO.Ports.SerialPort port = (System.IO.Ports.SerialPort)sender;
    
                while (port.BytesToRead > 0)//受信バイトがあるなら繰り返し
                {
                    int r = port.ReadByte();//1バイトずつ受信データを取り出す
                    if (r >= 0)
                    {
                        byte b = (byte)r;
                        switch (b)
                        {
                        case STX:
                            //ヘッダが見つかった
                            receiveBuffer.Clear();
                            receiveBuffer.Add(b);
                            break;
    
                        case EOT:
                            //フッタが見つかった
                            if (receiveBuffer.Count > 0)
                            {
                                receiveBuffer.Add(b);
                                receivedData = receiveBuffer.ToArray();
                                receiveBuffer.Clear();
                                isEOTReceived = true;
                            }
                            break;
                        default:
                            if (receiveBuffer.Count > 0)
                            {
                                receiveBuffer.Add(b);
                            }
                            break;
                        }
                    }
                }
            }
        }
    }
    #マイコンでもDMAでバッファに蓄えるやり方があるんですが…

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2018年7月31日 4:04 コードの余計な部分削除
    2018年7月31日 4:02
  • ありがとうございます。正直まだ構文というかクラスというかC#の「言葉」が理解出来ていません。コピペで済まさずに時間をかけて解読したいと思います。
    2018年7月31日 6:09