小弟不才,不是学软件出身,所以做上位机软件也是头一次,CSDN上也看到了很多关于线程之类的处理,确实不太明白。
这次单位要求用RS232通信,并接收数据后处理结果。
RS232收到上位机发送的START信号后,首先快速的返回"Ver=XX",然后隔个5秒或6秒(肯定10秒以内)后返回结果"CODE=XX",XX的不同代表了不同的返回结果,所以需要针对XX做进一步的处理(函数Display())。
但是由于两组数据之间间隔时间较长,DataReceived又是按字节触发,有时会认为第一组数据接收到后就结束,或者收到部分数据,然后就去执行Display()函数了,导致最终的结果肯定不对。我怎么保证我能每次都能收到完整的数据?
谢谢!

解决方案 »

  1.   

    可以在CODE=XX的后面打特殊的结束标志
      

  2.   

    ReadExisting();或者ReadTo();
      

  3.   

    比如说,文档中假设没有规定每一个信令用换行结束,那么龟腚了用什么结束呢?假设文档说类似“Ver=XX”这类指令,一律在等号右边有两个 ascii 字符(或者 unicode字符),两个字符之后就算是指令结束,这么这类也算是有个文档了!如果并没有文档,或者文档中没有这类规定,那就是缺乏基本概念了。
      

  4.   


    这就是编程设计问题。DataReceived 事件触发之后,你收到的字节本来就应该跟以前收到的内容一起、累积到一个集合中,例如一个 List<byte> 集合中。然后判断有没有一条完整的消息。如果有,就从中取出第一条消息,进行解析处理。如果没有就什么也不用做了。
      

  5.   

    楼上大神说过了,数据接收和处理要分离
    数据接收后根据规约判定报文是否完整,
     1.长度不够---->继续接收;
     2.长度恰好是一个完整的包 ----> 完成解析;
     3.长度不止一个包,循环解析;
      

  6.   


    这就是编程设计问题。DataReceived 事件触发之后,你收到的字节本来就应该跟以前收到的内容一起、累积到一个集合中,例如一个 List<byte> 集合中。然后判断有没有一条完整的消息。如果有,就从中取出第一条消息,进行解析处理。如果没有就什么也不用做了。我主要疑问在Display()函数应该放哪里?Send_Ins();  //发送函数//===============
    //数据处理
    //                if (txtBoxS1.Text.Length == 50)
    //                {
    //                    Display();
    //                }
    //                else
    //                    TestResult1_FailLength();
    //===============private List<byte> buffer1 = new List<byte>(4096);
    private void S1Com_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                int count=0;
                if (S1Com.IsOpen)
                {
                    try
                    {
                        do
                        {
                            count = S1Com.BytesToRead;
                            if (count <= 0)
                                break;
                            Byte[] receivedData = new byte[count];
                            S1Com.Read(receivedData, 0, count);
                            buffer1.AddRange(receivedData);
                            foreach (byte b in receivedData)
                            {
                                txtBoxS1.Text += Convert.ToChar(b);
                            }                    } while (S1Com.BytesToRead > 0);
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(ex.Message, "出错提示");
                        txtBoxS1.Text = "";
                    }
                    //数据处理
                    if (txtBoxS1.Text.Length == 50)
                    {
                        Display();
                    }
                    else
                        TestResult1_FailLength();
                }
            }由于一开始数据肯定不会满50个字符,程序一直会走到 TestResult1_FailLength()函数里面。
    如果我把数据处理那段if...else..,放到Send_Ins();函数后面,也不会等S1Com_DataReceived()处理完才做,所以不知所措。麻烦请指导。
      

  7.   


    如果一个包中间TimeOut呢?
      

  8.   

    这边就是发送"<<START>>"这九个字符public string strSendIns = "<<START>>";
    byte[] byteBuffer = Encoding.ASCII.GetBytes(strSendIns);S1Com.Write(byteBuffer, 0, byteBuffer.Length);而串口设置如下:S1Com.PortName = cbSerial1.Text;
    S1Com.BaudRate = Convert.ToInt32(BaudRate);
    S1Com.DataBits = Convert.ToInt32(DataBits);
    S1Com.StopBits = StopBits.One;
    S1Com.Parity = Parity.None;我不明白你指的报文起始符,结束符,校验符是什么?串口默认是从低电平作为start bit。
      

  9.   

    定义一个全局变量list,或者stringbuiler;
    在你的receive函数中,
    1.接收到的数据增加到list中,
    2.然后调用display,判断是否接收完整,如果完整接收到,解释数据,并将解释完的数据从list中删除。如果没有接收到完整的数据,返回。接收到非法数据,删除非法数据;
      

  10.   


    如果一个包中间TimeOut呢?如果timeout,
    接收侧直接断开连接即可
    让client重新发起连接,重新发送数据
      

  11.   


    如果一个包中间TimeOut呢?如果timeout,
    接收侧直接断开连接即可
    让client重新发起连接,重新发送数据
    “接收方直接断开连接”是指断开串口嘛?