我的程序和一台医疗仪器通讯。通讯建立后,该医疗仪器每次发送一行数据(但我也不确定一行数据是分次发还是一次性发,因为这个程序不是我写的,但从结果上判断,应该是一次性发送的)。结果我的程序一般情况下先收200字节,然后再收48字节(偶尔也会一次性收248字节,所以我判断医疗仪器是一次性发送一行数据)。
    我的程序是在ReveiveData事件中接收数据的,另外,ReceivedBytesThreshold属性设置为1。我的程序已经依靠数据侦的首尾标志解决分段接收的问题,但以下疑问在心中,仍无法得到答案    但为什么我的程序是先收200字节,再收48字节?我的ReadBufferSize已经设置为1M了,为何没有效果?还请高手解答。
  
    另:还有没有其它数据接收方式,能够一次性接收完对方一次性发送过来的数据?

解决方案 »

  1.   

    ReceivedBytesThreshold获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数读取当前缓冲区中的所有数据可用ReadExisting(),有时可以加个thread.sleep()待串口上数据发完
      

  2.   

    你的一个数据帧是多少啊,我的数据包是固定的,就是208个字节。所以
    我在接收事件里用byte[] data=new int[208];
                for (int i = 0; i < 208; i++)
                {
                  data[i] = Convert.ToByte(serialPort1.ReadByte());
                }
    处理完之后再用serialport1.discadinbuffer();
      

  3.   

    ReceivedBytesThreshold 才是触发缓存区字节的大小吧
    你把他设置成200看看……
      

  4.   

    byte[] data = new byte[this.serialPort1.BytesToRead];
    selMonitor.Read(data, 0, data.Length);如果你不设置一次读取的大小,程序会一次完整把缓存里的数据全部提走.
    上面的就可以.(尽量用线程来读)
      

  5.   

    代码sp即为串口,其中ReceivedBytesThreshold=1。因为上位机有多种,而且程序不是我写的,所以我无法定义数据桢的格式。我也知道ReceivedBytesThreshold=200,就会收到>=200字节后才激发事件,但由于上位机程序有多种,发送的字节数有时候一次仅一个(如开始标志或结束标志),所以只能将ReceivedBytesThreshold设置为1。大家帮我看看程序,这种接收方法是不是有什么问题。
       现在最关键的是,我总怀疑上位机是一次性发了一条数据(约300-500字节),而我的程序却分了N次接收后再合并的。现在有没有方法能够做到对方发送一条数据,而我这边也仅只要收一次。ReadExisting()方法不能用,因为它返回字符串,而我的数据还需要分析二进制后再解码的。有兄弟说用sleep,不知道能不能行,还没试。        protected void ReceiveBySubsection()
            {
                byte[] readBuffer = new byte[BUFFERSIZE];
                //关键就在此方法上,是不是read方法不能一次性把缓冲区中的所有数据都读完?
                 //我也怀疑是ReceivedBytesThreshold=1导致频繁激发Receive事件,但仅是怀疑
                int count = sp.Read(readBuffer, 0, readBuffer.Length);            //接收到新数据,清空原有数据,StartWithFlag为自己编写的方法            if (StartWithFlag(readBuffer))
                {
                    datas = new List<byte>();
                }
                if (datas == null)
                {
                    OnErrorReceived(new ErrorReceiveEventArgs("一次性分段接收数据出错,未接收到起始标志。", true));
                    return;
                }
                //CopyDataToList将数据追加到List集合,是自定义的方法
                CopyDataToList(datas, readBuffer, count);
                //判断有没有收到结束标志
                if (EndWithFlag(readBuffer))
                {
                    //进行下一步的解码和分析数据的操作
                    DecodeAndAnalyse(datas);
                }
            }
      

  6.   

    我的意见是不用ReveiveData这个事件,我在做串口程序的时候也遇到了这样的问题的,一次性发送的内容却莫名其妙的分了两次接收
    你可以自己开一个线程来处理就好了,如果发送的命令含有固定的结束符,可以用ReadTo函数,如果没有可以用Read或者ReadExist等等
      

  7.   


    Thread.Sleep(50);
                                
                    if (p.BytesToRead > 0)
                    {
                        //循环接收
                        string strData = p.ReadExisting();
                       
                    }这样试试
      

  8.   

    ReceivedBytesThreshold 这个属性不用改,默认就是1
      

  9.   

    read事件不太好用,你定义100字节触发,但是串口接受的数据不是1个字节一个字节来的,有可能一下来两个,有可能就超过了100个字节,所以就不准了。
      

  10.   

    请参考一下下面的方法。
    技术要点: 
    (1).首先,SerialPort的ReceivedBytesThreshold先设置成1,表示只要有1个字符送达端口时便触发DataReceived事件 
    (2).当DataReceived触发时,先把ReceivedBytesThreshold设置成一个比较大的值,达到读取本次端口数据时,不再触发DataReceived. 
    (3).循环读取端口中的数据,直至读完。 
    (4).移除读取数据中的非法字符。 
    (5).触发一个后台线程处理收到的数据。 
    (6).在finally中把ReceivedBytesThreshold重置回1         private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 
            { 
                if (sender.GetType() != typeof(System.IO.Ports.SerialPort)) 
                { 
                    return; 
                } 
                string strReceive = string.Empty; 
                string strCollect = string.Empty; 
                System.IO.Ports.SerialPort comPort = (System.IO.Ports.SerialPort)sender;             try 
                { 
                    comPort.ReceivedBytesThreshold = comPort.ReadBufferSize; 
                    while (true) 
                    { 
                        strReceive = comPort.ReadExisting(); 
                        if (string.Equals(strReceive, string.Empty)) 
                        { 
                            break; 
                        } 
                        else 
                        { 
                            strCollect += strReceive; 
                            Application.DoEvents(); 
                            Thread.Sleep(100); 
                        } 
                    } 
                    strCollect = strCollect.Replace("\0", string.Empty); 
                    strCollect = strCollect.Replace("\r\n", string.Empty); 
                    strCollect = strCollect.Replace("\r", string.Empty); 
                    strCollect = strCollect.Replace("\n", string.Empty);                 if (!this.bIsHandleCom) 
                    { 
                        this.bIsHandleCom = true; 
                        mReceiveData = strCollect; 
                        if (ReceiveDataParserEvent != null) 
                            ReceiveDataParserEvent(mReceiveData); 
                        if (ThreadReceiveParser != null && !ThreadReceiveParser.IsAlive) 
                        { 
                            ThreadReceiveParser.Start(); 
                        } 
                    }             } 
                catch (Exception ex) 
                { 
                    MessageBox.Show(this, ex.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); 
                } 
                finally 
                { 
                    comPort.ReceivedBytesThreshold = 1; 
                } 
            }