C# SerialPort 使用DataReceived接口利用空闲中断原理接收完整一帧数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sensiki/article/details/78132702

说明

  • 使用SerialPort类
  • 使用SerialPort.DataReceived 接收事件
  • DataReceived事件触发无规律,不可作为一帧数据的判断
  • 数据接收也可使用单独一个线程轮询判断,判断更为精确,但是要完全占用一个线程,无堵塞,费资源。
  • 欢迎补充指导

开启串口

SerialPort mySerialPort;//本地串口
mySerialPort = new SerialPort(comName);
mySerialPort.BaudRate = (int)dr.baud;//波特率
mySerialPort.DataBits = Convert.ToInt32(dr.databits);//数据位
mySerialPort.StopBits = (StopBits)Convert.ToInt32(dr.stopbits);//停止位
mySerialPort.Parity = (Parity)Enum.Parse(typeof(Parity), dr.parity);//校验位
mySerialPort.WriteTimeout = 500;
LocalPort localport = new LocalPort(mySerialPort);
if (mySerialPort.IsOpen == false)
{
    Console.Write("open " + comName + " Error.\r\n");
    return response; ;
}
else
{
    localport.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(ReceiveFromDevice);//打开成功则创建接收数据事件
    localport.LocalPortName = comName;
    localportList.Add(comName, localport);
    Console.Write("open " + comName + " Ok.\r\n");

}

串口接收事件

接收到数据后使用委托处理,更为高效,也防止堵塞串口接收数据事件

//本地串口事件  接收来自设备发向本地串口的数据
private static void ReceiveFromDevice(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort serialPort = (SerialPort)sender;

    foreach (string key in localportList.Keys)
    {
        if (serialPort.PortName == key)
        {
            LSPReceiveDelegate lsprd = new LSPReceiveDelegate(Receive);
            lsprd(localportList[key]);
        }
    }        
}    

数据处理判断

使用类似空闲中断方法区分一帧数据,对缓存数据大小也做了限制,同时对最后一组数据做了定时器判断。

public static void Receive(LocalPort localPort)
{
    try
    {
        SerialPort LP = localPort.port;
        int revcount_new = LP.BytesToRead;
        TimeSpan span;
        int oneByteTime = 0;
        if (LP.Parity == Parity.None)
            oneByteTime = 1000000 / (LP.BaudRate / 10);
        else
            oneByteTime = 1000000 / (LP.BaudRate / 11);
        int diffCount = 0;
        try
        {
            if (localPort.isNewFrame)
                localPort.dt = DateTime.Now;
            DateTime dt = DateTime.Now;
            span = dt - localPort.dt;
            localPort.dt = dt;
            diffCount = revcount_new - localPort.revcount;
            localPort.revcount = revcount_new;
            if (span.Ticks > ((diffCount + 3) * oneByteTime * 10))
            {
                byte[] recvBytes = new byte[LP.BytesToRead];
                LP.Read(recvBytes, 0, recvBytes.Length);
                //string recvData = LP.ReadExisting();
                localPort.revcount = 0;
                SendToCloudDelegate stcd = SendToCloud;
                stcd("receive", LP.PortName, null, ByteToHexStr(recvBytes));
                localPort.isNewFrame = true;
            }
            else if (localPort.revcount > 2048)
            {
                byte[] recvBytes = new byte[LP.BytesToRead];
                LP.Read(recvBytes, 0, recvBytes.Length);
                //string recvData = LP.ReadExisting();
                localPort.revcount = 0;
                SendToCloudDelegate stcd = SendToCloud;
                stcd("receive", LP.PortName, null, ByteToHexStr(recvBytes));
                localPort.isNewFrame = true;
            }
            else
            {
                localPort.isNewFrame = false;
                try
                {
                    localPort.timer.Stop();
                    localPort.timer.Close();
                }
                catch
                { }
                localPort.timer = new System.Timers.Timer(10);
                localPort.timer.Elapsed += new System.Timers.ElapsedEventHandler(LSPTimeOut); //到达时间的时候执行事件;   
                localPort.timer.AutoReset = false;   //设置是执行一次(false)还是一直执行(true);   
                localPort.timer.Enabled = true;     //是否执行System.Timers.Timer.Elapsed事件;
                localPort.timer.Start();
            }
        }
        catch
        {
            Console.WriteLine(LP.PortName + "closed!");
            SendToProcess(LP.PortName + "closed!");
        }


    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    //}

}

使用该方法可以有效区分接收一帧数据,但是也存在弊端。如最后一帧数据会有一个定时器定时的时间延时,如果数据包发送比较缓慢,每一帧数据都存在定时器那个时间的延时。

猜你喜欢

转载自blog.csdn.net/sensiki/article/details/78132702