none
シリアル通信のデータ受信イベントについて RRS feed

  • 質問

  • シリアル通信でデータを受信する際、

    serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

    のように、SerialDataReceivedEventを使用していますが、1度のデータ受信イベントで受け取れるデータ長は環境によって変わるのでしょうか?

    例えば、250バイトのデータを受信しようとしていますが、現在1回のイベントで8バイト受信できているため、計32回の受信イベントが発生して、ようやく250バイト全てを受信できていました。

    この8バイトという数字をもっと大きくできれば、データ受信イベント発生数を減らせるため、処理速度が上がると考えているのですが、意図的に変えることはできるのでしょうか。

    宜しくお願い致します。


    • 編集済み Fkaworu 2018年12月12日 2:10
    2018年12月12日 2:09

回答

  • SerialPortクラスのReceivedBytesThreasholdプロパティがイベント発生までの最低バイト数です。

    途中で通信の欠落が発生しないという前提ならReceivedBytesThreasholdを250バイトにすることだってできます。

    このバイト数以上を受信しないとイベント発生しないので、バイト数未満だといつまでもイベント発生しません。
    ときどきバッファにたまってないか確認する必要があります。

    namespace ConsoleApp1
    {
        using System;
    
        class Program
        {
            private static System.IO.Ports.SerialPort p1;
            private static System.IO.Ports.SerialPort p2;
            private static System.Threading.Timer timer;
            private static DateTime timeout;
    
            static void Main(string[] args)
            {
    
                using (p1 = new System.IO.Ports.SerialPort("COM1"))//COM1とCOM2がクロスケーブルで接続されているとして
                using (p2 = new System.IO.Ports.SerialPort("COM2"))
                using (timer = new System.Threading.Timer(OnTimer, p1, -1, -1))
                {
                    p1.BaudRate = 9600;
                    p2.BaudRate = 9600;
                    //p1.ReadBufferSize=10000;
    
                    p1.DataReceived += P1_DataReceived;
                    p1.ReceivedBytesThreshold = 250; //バッファにたまったらイベント呼び出しをするバイト数
                    p1.Open();
                    p2.Open();
    
                    timeout = DateTime.Now.AddSeconds(1);
                    timer.Change(100, 100);
    
                    System.Threading.Tasks.Task.Run(() =>
                    {
                        //別スレッドで256バイト送ってみる
                        for (int i = 0; i < 256; i++)
                        {
                            p2.Write((i % 10).ToString());
                        }
                    });
    
                    Console.ReadLine();
                }
    
            }
    
            private static void OnTimer(object state)
            {
                if (timeout <= DateTime.Now)
                {
                    Console.WriteLine("TIME OUT");
                    System.IO.Ports.SerialPort port = (System.IO.Ports.SerialPort)state;
                    Read(port);
                }
            }
    
            private static void P1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                System.IO.Ports.SerialPort port = (System.IO.Ports.SerialPort)sender;
                Read(port);
            }
    
            private static void Read(System.IO.Ports.SerialPort port)
            {
                lock (port)
                {
                    int count = port.BytesToRead;
                    if (count > 0)
                    {
                        byte[] bs = new byte[count];
                        int red = port.Read(bs, 0, bs.Length);
    
                        Console.WriteLine(count.ToString() + "\t" + red.ToString() + "\t" + port.Encoding.GetString(bs, 0, red));
    
                        timeout = DateTime.Now.AddSeconds(1);
                    }
                }
    
            }
        }
    }
    #間にドライバとSerialPortクラスのバッファが入るので...

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

    • 回答としてマーク Fkaworu 2019年2月18日 6:35
    2018年12月12日 5:22

すべての返信

  • UART 16550互換ですと、16バイトバッファですので、これ以上貯めこんでから割り込むとバッファが溢れます。使いのハードウェアのバッファサイズをご確認ください。
    2018年12月12日 4:14
  • SerialPortクラスのReceivedBytesThreasholdプロパティがイベント発生までの最低バイト数です。

    途中で通信の欠落が発生しないという前提ならReceivedBytesThreasholdを250バイトにすることだってできます。

    このバイト数以上を受信しないとイベント発生しないので、バイト数未満だといつまでもイベント発生しません。
    ときどきバッファにたまってないか確認する必要があります。

    namespace ConsoleApp1
    {
        using System;
    
        class Program
        {
            private static System.IO.Ports.SerialPort p1;
            private static System.IO.Ports.SerialPort p2;
            private static System.Threading.Timer timer;
            private static DateTime timeout;
    
            static void Main(string[] args)
            {
    
                using (p1 = new System.IO.Ports.SerialPort("COM1"))//COM1とCOM2がクロスケーブルで接続されているとして
                using (p2 = new System.IO.Ports.SerialPort("COM2"))
                using (timer = new System.Threading.Timer(OnTimer, p1, -1, -1))
                {
                    p1.BaudRate = 9600;
                    p2.BaudRate = 9600;
                    //p1.ReadBufferSize=10000;
    
                    p1.DataReceived += P1_DataReceived;
                    p1.ReceivedBytesThreshold = 250; //バッファにたまったらイベント呼び出しをするバイト数
                    p1.Open();
                    p2.Open();
    
                    timeout = DateTime.Now.AddSeconds(1);
                    timer.Change(100, 100);
    
                    System.Threading.Tasks.Task.Run(() =>
                    {
                        //別スレッドで256バイト送ってみる
                        for (int i = 0; i < 256; i++)
                        {
                            p2.Write((i % 10).ToString());
                        }
                    });
    
                    Console.ReadLine();
                }
    
            }
    
            private static void OnTimer(object state)
            {
                if (timeout <= DateTime.Now)
                {
                    Console.WriteLine("TIME OUT");
                    System.IO.Ports.SerialPort port = (System.IO.Ports.SerialPort)state;
                    Read(port);
                }
            }
    
            private static void P1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                System.IO.Ports.SerialPort port = (System.IO.Ports.SerialPort)sender;
                Read(port);
            }
    
            private static void Read(System.IO.Ports.SerialPort port)
            {
                lock (port)
                {
                    int count = port.BytesToRead;
                    if (count > 0)
                    {
                        byte[] bs = new byte[count];
                        int red = port.Read(bs, 0, bs.Length);
    
                        Console.WriteLine(count.ToString() + "\t" + red.ToString() + "\t" + port.Encoding.GetString(bs, 0, red));
    
                        timeout = DateTime.Now.AddSeconds(1);
                    }
                }
    
            }
        }
    }
    #間にドライバとSerialPortクラスのバッファが入るので...

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

    • 回答としてマーク Fkaworu 2019年2月18日 6:35
    2018年12月12日 5:22