首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

求串口通讯达人解答,遇到了一个很蹊跷的有关问题

2012-12-28 
求串口通讯达人解答,遇到了一个很蹊跷的问题先上代码还有种情况是:第一次读取了16个字节,在Thread.Sleep(1

求串口通讯达人解答,遇到了一个很蹊跷的问题
先上代码



还有种情况是:第一次读取了16个字节,在Thread.Sleep(10)后,serialPort1.BytesToRead=0,于是数据就接收不完整了,此时就会跳出while (serialPort1.BytesToRead > 0)循环,我很奇怪呀,这10ms的时间里,用示波器可以看到下位机是有数据传送过来的,为什么这些数据没有进入serialPort1的缓冲区呢?
一样的代码,一样的波特率,为什么有时候进入触发事件时,缓冲区读到的字节数是16,有时候会超过16?为什么有时候Thread.Sleep(10);剩下的数据会存入缓冲区,有时候却不会?

不知道描述清楚了没,求达人解答呀求串口通讯达人解答,遇到了一个很蹊跷的有关问题
[解决办法]
这应该是系统进程调度产生的结果,一个进程不是时时刻刻都在运行的,而每次运行的时间间隔也不一定相等,所以会导致每次读到数据量不等的情况

纯属个人意见 仅供参考
[解决办法]
串口编程时有任何的延时行为都有可能导至接收丢数据。

因此我的策略是使用异步或者开一个线程去读数据(这就确保了不会有延时)。读到数据后再使异步调用处理函数(这样就可以无视处理时间了)。自从使用了这个方案后从来没有发生过丢数据的情况(受干扰除外)。

附代码


serialPort = new System.IO.Ports.SerialPort();
serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort_DataReceived);
..........
serialPort.Open();




        void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.AboveNormal;//调高优先级,保证线程不会被其它线程阻塞。
            if (e.EventType == System.IO.Ports.SerialData.Chars)
            {
                while (serialPort.BytesToRead > 0)
                {


                    BuffEventArgs arg = new BuffEventArgs();
                    arg.Connection = this;
                    arg.Data = new byte[512];
                    arg.Length = serialPort.Read(arg.Data, 0, arg.Data.Length);
                    CallOnReceiveDataInvoke(this, arg); //使用异步方式引发接收事件                  
                }
            }
        }




[解决办法]
引用:
引用:引用:引用:引用:引用:serialPort1_DataReceived 用这个必须要有协义头才行
如 
 协议号
 长度
 内容
这三个


要是不明白百度一下,Socket粘包原……


帮你实现了简单的字节缓冲器。



 /// <summary>
    /// 字节缓冲器
    /// </summary>
    public class ByteQueue
    {
        private List<byte> m_buffer = new List<byte>();
        public bool Find()
        {
            if (m_buffer.Count == 0)
                return false;
            int HeadIndex = m_buffer.FindIndex(o => o == 0xAA);

            if (HeadIndex == -1)
            {
                m_buffer.Clear();
                return false; //没找到AA
            }

            else if (HeadIndex != 0) //不为开头移掉之前的字节
            {
                if (HeadIndex > 1)
                    m_buffer.RemoveRange(0, HeadIndex);
            }

            int length= GetLength();

            if (m_buffer.Count <length)
            {


                return false;
            }

            int TailIndex = m_buffer.FindIndex(o => o == 0x55); //查找55的位置

            if (TailIndex == -1)
            {
                //这一步为防止连发一个AA开头的包后,没发55,而又发了一个AA
                int head = m_buffer.FindLastIndex(o => o == 0xAA);
                if (head > -1)
                {
                    m_buffer.RemoveRange(0, head);
                }
                return false;
            }
            else if (TailIndex + 1 != length) //计算包尾是否与包长度相等
            {
                m_buffer.RemoveRange(0, TailIndex);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 命令类型
        /// </summary>
        /// <returns></returns>
        public byte Cmd()
        {
            if (m_buffer.Count >= 2)
            {
                return m_buffer[1];
            }
            return 0;
        }

        /// <summary>
        /// 序号
        /// </summary>
        /// <returns></returns>
        public byte Number()
        {
            if (m_buffer.Count >= 3)
            {
                return m_buffer[2];


            }
            return 0;
        }

        /// <summary>
        /// 包长度
        /// </summary>
        /// <returns></returns>
        public int GetLength()
        {
            int len = 5;//AA 命令类型 序号 校验和 55
            if (m_buffer.Count >= 3)
            {
                switch (m_buffer[2]) //第三字节为序号
                { 
                    case 0x00: //序号
                        return len + 16;
                    case 0x01: //序号
                        return len + 10;
                    case 0x02: //序号
                        return len + 12;
                }
            }
            return 0;
        }
        /// <summary>
        /// 提取数据
        /// </summary>
        public void Dequeue(byte[] buffer, int offset,int size)
        {
            m_buffer.CopyTo(0,buffer,offset,size);
            m_buffer.RemoveRange(0, size);
        }

        /// <summary>
        /// 队列数据
        /// </summary>
        /// <param name="buffer"></param>
        public void Enqueue(byte[] buffer)
        {
            m_buffer.AddRange(buffer);
        }
    }






这是调用例子




 private ByteQueue queue = new ByteQueue();
 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int len = serialPort1.BytesToRead;
            if (len > 0)
            {
                byte[] temp = new byte[len];
                serialPort1.Read(temp, 0, len);
                queue.Enqueue(temp);
                while (queue.Find()) //while可处理同时接收到多个AA ... 55 ,AA...55的包
                {
                    int length = queue.GetLength();
                    byte[] readBuffer = new byte[len];
                    queue.Dequeue(readBuffer, 0, length);
                    OnReceiveData(readBuffer); //<这里自己写一个委托吧就OK了
                }

            }

        }

热点排行