2

我通过串行端口定期接收一些数据,以便绘制它并做更多的事情。为了达到这个目的,我将数据从我的微控制器发送到我的计算机,并带有一个标头,它指定了每个数据包的长度。

除了最后一个细节外,我的程序运行良好且运行良好。当标头指定长度时,我的程序在达到该字节数之前不会停止。因此,如果由于某种原因丢失了一个数据包中的某些数据,程序将等待并获取下一个数据包的开头......然后开始真正的问题。从那一刻起,一切都失败了。

我想过每 0.9 秒升起一个计时器(包裹每秒来一次),它会发出命令以返回等待并重置变量。但我不知道该怎么做,我试过但在运行时出现错误。由于 IndCom(请参阅下一个代码)在某些功能中间重置,并且出现“索引超出范围”时出现错误。

我附上我的代码(没有计时器)

private void routineRx(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        try
        {
            int BytesWaiting;


            do
            {
                BytesWaiting = this.serialPort.BytesToRead;
                //Copy it to the BuffCom
                while (BytesWaiting > 0)
                {
                    BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
                    IndCom = IndCom + 1;
                    BytesWaiting = BytesWaiting - 1;
                }

            } while (IndCom < HeaderLength);
            //I have to read until I got the whole Header which gives the info about the current packet

            PacketLength = getIntInfo(BuffCom,4);

            while (IndCom < PacketLength)
            {
                BytesWaiting = this.serialPort.BytesToRead;
                //Copy it to the BuffCom
                while (BytesWaiting > 0)
                {
                    BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
                    IndCom = IndCom + 1;
                    BytesWaiting = BytesWaiting - 1;
                }
             }

            //If we have a packet--> check if it is valid and, if so, what kind of packet is
            this.Invoke(new EventHandler(checkPacket));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }

我是面向对象编程和 c# 的新手,所以请宽容!非常感谢你

4

1 回答 1

1

你可以做的是使用秒表。

const long COM_TIMEOUT = 500;

Stopwatch spw = new Stopwatch();
spw.Restart();
while (IndCom < PacketLength)
{
    //read byte, do stuff
    if (spw.ElapsedMilliseconds > COM_TIMEOUT) break;  //etc
}

在开始时重新启动秒表并检查每个 while 循环中的时间,然后在超时时中断(并清理)。即使您只期望几个字节,900 毫秒也可能太多了。Com 流量非常快 - 如果您没有立即获得全部内容,它可能不会出现。

我喜欢在通信协议(如 [CR] 等)中使用终止字符。这使您可以阅读直到找到终止字符,然后停止。这可以防止读入下一个命令。即使您不想使用终止字符,也可以将代码更改为以下内容:

 while (IndCom < PacketLength)
 {
     if (serialPort.BytesToRead > 0) 
     {
         BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
         IndCom++;             
     }
  }

它允许您在达到数据包大小时停止,将任何剩余的字符留在缓冲区中以供下一轮通过(即:下一个命令)。您也可以在上面添加秒表超时。

关于终止字符的另一个好处是您不必提前知道数据包应该多长时间 - 您只需阅读直到到达终止字符,然后在获得它后处理/解析整个内容。它使您的两步端口读入一步端口读。

于 2012-11-26T12:05:51.480 回答