none
SerialPort.DataReceived 接收数据延迟 RRS feed

  • 问题

  •     大家好,我在windows 7 .net framework 4.0 框架下编写的串口通讯程序,接收到数据延迟。源码如下:

          
    using System;
    using System.IO.Ports;
    using System.Linq;
    using Common.Log;
    
    namespace Common.SerialComm
    {
        /// <summary>
        /// 串口服务的抽象类
        /// </summary>
        public abstract class SerialPortCommunication
        {
            /// <summary>
            ///串口
            /// </summary>
            private ExSerialPort _serialProt = null;
    
            /// <summary>
            /// 通讯的锁
            /// </summary>
            private readonly object _commLocker = new object();
    
            #region 属性
    
            /// <summary>
            /// 串口是否被打开
            /// </summary>
            public bool IsOpen
            {
                get 
                {
                    lock (_commLocker)
                    {
                        if (_serialProt == null)
                        {
                            return false;
                        }
    
                        return _serialProt.IsOpen;
                    }
                }
            }
    
            /// <summary>
            /// 波特率
            /// </summary>
            public int BaudRate
            {
                get;
                private set;
            }
    
            public string Port
            {
                get;
                private set;
            }
    
            #endregion
    
            #region 公有方法
    
            public SerialPortCommunication(string port, int baudRate)
            {
                this.Port = port;
                this.BaudRate = baudRate;
            }
    
            /// <summary>
            /// 开启服务监听
            /// </summary>
            /// <param name="port"></param>
            /// <returns></returns>
            public virtual bool StartService()
            {
                lock (_commLocker)
                {
                    try
                    {
                        if (string.IsNullOrEmpty(this.Port))
                        {
                            return false;
                        }
    
                        string[] arrNames = SerialPort.GetPortNames();
                        string find = arrNames.FirstOrDefault(obj => obj.ToUpper().Equals(this.Port.ToUpper()));
                        if (find != null)
                        {
                            _serialProt = new ExSerialPort(this.Port);
                            _serialProt.Parity = Parity.None;
                            _serialProt.StopBits = StopBits.One;
                            _serialProt.BaudRate = BaudRate;
                            _serialProt.WriteTimeout = 500;
                            _serialProt.ReadTimeout = 500;
                            _serialProt.DataReceived += SerialProt_DataReceived;
                            _serialProt.Open();
    
                            LogHelper.Info("打开串口" + this.Port.ToString() + "成功");
                            return true;
                        }
                    }
                    catch (Exception ex)
                    {
                        _serialProt.Destroy();
                        _serialProt = null;
                        LogHelper.Info("打开串口" + this.Port.ToString() + "失败", ex);
                    }
                    return false;
                }
            }
    
            /// <summary>
            /// 停止服务
            /// </summary>
            public virtual void StopService()
            {
                try
                {
                    lock (_commLocker)
                    {
                        if (_serialProt != null)
                        {
                            _serialProt.Destroy();
                            LogHelper.Info("关闭串口" + _serialProt.PortName.ToString() + "成功");
                            _serialProt = null;
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error("串口关闭失败", ex);
                }
            }
    
            /// <summary>
            /// 发送消息
            /// </summary>
            /// <param name="message"></param>
            /// <returns></returns>
            public bool SendMessage(byte[] message, int length = 0)
            {
                try
                {
                    lock (_commLocker)
                    {
                        if (_serialProt == null || !_serialProt.IsOpen)
                        {
                            return false;
                        }
    
                        if (length == 0)
                        {
                            _serialProt.Write(message, 0, message.Length);
                        }
                        else
                        {
                            _serialProt.Write(message, 0, length);
                        }
                        return true;
                    }
                }
                catch
                {
                }
                return false;
            }
    
            #endregion
    
            protected virtual void OnReceiveMessage(byte[] bytes)
            {
            }
    
            private void SerialProt_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                try
                {
                    lock (_commLocker)
                    {
                        int byteCount = _serialProt.BytesToRead;
                        byte[] receiveByte = new byte[byteCount];
                        _serialProt.Read(receiveByte, 0, byteCount);
                        _serialProt.DiscardOutBuffer();
                        if (receiveByte != null && receiveByte.Length > 0)
                        {
                            OnReceiveMessage(receiveByte);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Fatal(string.Format("{0}接收数据异常", _serialProt.PortName), ex);
                }
            }
        }

    下面是用accessport抓包工具抓取的延迟数据

    76298	下午 4:56:16.812	0.00002717	Robot.Server.e	IOCTL_SERIAL_PURGE                  	COM9	SUCCESS	Purge: TXABORT TXCLEAR	
    76299	下午 4:56:16.872	0.00018233	Robot.Server.e	IRP_MJ_WRITE                        	COM9	SUCCESS	Length: 11, Data: AA 55 CC 81 03 00 85 00 03 0B E2 	
    76300	下午 4:56:16.875	0.33578993	Robot.Server.e	IOCTL_SERIAL_WAIT_ON_MASK           	COM9	SUCCESS		
    76301	下午 4:56:17.206	0.00019561	Robot.Server.e	IRP_MJ_WRITE                        	COM9	SUCCESS	Length: 22, Data: AA 55 CC 81 10 00 01 00 05 0A 64 00 01 00 00 00 00 00 00 00 E3 76 	
    76302	下午 4:56:17.211	0.30367487	Robot.Server.e	IOCTL_SERIAL_WAIT_ON_MASK           	COM9	SUCCESS		
    76303	下午 4:56:17.508	0.00018172	Robot.Server.e	IRP_MJ_WRITE                        	COM9	SUCCESS	Length: 11, Data: AA 55 CC 81 03 00 85 00 03 0B E2 	
    76304	下午 4:56:17.515	0.20769979	Robot.Server.e	IOCTL_SERIAL_WAIT_ON_MASK           	COM9	SUCCESS		
    76305	下午 4:56:17.707	0.00006943	Robot.Server.e	IRP_MJ_READ                         	COM9	SUCCESS	Length: 39, Data: AA 55 CC 81 03 06 08 00 74 2B 77 6D CC 1E AA 55 CC 81 10 00 01 00 05 4E 0A AA 55 CC 81 03 06 08 00 74 2B 77 6B 4C 1C 	
    76306	下午 4:56:17.707	0.00002294	Robot.Server.e	IOCTL_SERIAL_PURGE                  	COM9	SUCCESS	Purge: TXABORT TXCLEAR	
    76307	下午 4:56:17.710	0.00016905	Robot.Server.e	IRP_MJ_WRITE                        	COM9	SUCCESS	Length: 11, Data: AA 55 CC 82 03 00 00 00 02 DB F8 	
    76308	下午 4:56:17.723	0.04780491	Robot.Server.e	IOCTL_SERIAL_WAIT_ON_MASK           	COM9	SUCCESS		
    76309	下午 4:56:17.723	0.00005675	Robot.Server.e	IRP_MJ_READ                         	COM9	SUCCESS	Length: 12, Data: AA 55 CC 82 03 04 00 1E 00 20 29 25 	
    76310	下午 4:56:17.724	0.00003381	Robot.Server.e	IOCTL_SERIAL_PURGE                  	COM9	SUCCESS	Purge: TXABORT TXCLEAR


    求各位大神指点方向。

    2019年4月23日 8:41

全部回复

  • 串口在实际使用中如果想一次性接收完整的一条信息的几率并不大。

    如果你是发送一次 然后想要接收一个数据的话,最粗暴的方式就是sleep一段时间再接收。

    如果单纯的要接收完整数据的话,需要自己对每次接收的数据进行二次处理,判断接收数据包的头和尾

    大概思路是,接收,寻找包头,找到后寻找包尾,将头尾数据拿走,将剩余的数据与下一次接收的数据拼接,然后再寻找包头

    2019年4月23日 12:23
  • 谢谢你的回复, 我的实现跟你的思路是一样的。我遇到的问题是: 发送一条指令,超时300ms,没收到; 再发一条指令,超时300ms,还没收到;再发一条指令, 收到了3条回复指令。这会不会跟串口驱动的缓存区有关或跟电脑的稳定性有关。
    2019年4月24日 1:40

  • Hi  tanghl,

    >>谢谢你的回复, 我的实现跟你的思路是一样的。我遇到的问题是: 发送一条指令,超时300ms,没收到; 再发一条指令,超时300ms,还没收到;再发一条指令, 收到了3条回复指令。这会不会跟串口驱动的缓存区有关或跟电脑的稳定性有关。

    你的这个现象就比较奇怪了。这个你需要检查下你的串口设备,你连接的设备是否按照你的指令正确上传。 首先排除你的程序问题,你可以使用串口模拟器来测试。 然后排查连接你串口设备的问题。

    下面的博客可能对你有些帮助。

    C#串口介绍以及简单串口通信程序设计实现

    C#串口通信数据不完整

    C# 解决串口接收数据不完整


    Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet. 


    Best Regards

    Yong Lu

    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年4月24日 1:49
    版主
  • 出现的概率很低, 测试结果:几个小时出现一次延迟。我先试一下你的方案排查一下,谢谢了。
    2019年4月24日 2:38
  • 个人感觉和串口硬件设备的性能与传输距离有关。

    但是超时300ms都没接收到硬件可能有问题,以前我使用串口通讯一般性近距离20ms-100ms延迟,中远距离200ms以内。

    2019年4月28日 5:59