串行端口查询和数据处理(Serial Port Polling and Data handling)

2019-07-20 16:07发布

我想从几个串口从传感器通过微控制器读取。 每个串行端口将获得超过2000个测量(每个测量为7个字节,所有十六进制)。 他们都在同一时间发射。 现在我是从4个串口轮询。 另外,我每次测量转换成字符串,并将其追加到一个StringBuilder。 当我完成接收数据时,他们将在输出中的文件。 问题是CPU消耗是非常高的,范围从80%至100%。

我去了,虽然一些文章,把Thread.sleep代码(100)结尾。 它减少了CPU的时候没有数据到来。 我也把在Thread.sleep代码每个轮询的末尾时BytesToRead小于100。不仅有助于在一定程度上。

可有人提出一个解决方案,从串口轮询和处理,我得到的数据? 也许追加每次我得到的东西引起该问题的时间?

//I use separate threads for all sensors
private void SensorThread(SerialPort mySerialPort, int bytesPerMeasurement, TextBox textBox,     StringBuilder data)
    {
        textBox.BeginInvoke(new MethodInvoker(delegate() { textBox.Text = ""; }));

        int bytesRead;
        int t;
        Byte[] dataIn;

        while (mySerialPort.IsOpen)
        {
            try
            {
                if (mySerialPort.BytesToRead != 0)
                {
                  //trying to read a fix number of bytes
                    bytesRead = 0;
                    t = 0;
                    dataIn = new Byte[bytesPerMeasurement];
                    t = mySerialPort.Read(dataIn, 0, bytesPerMeasurement);
                    bytesRead += t;
                    while (bytesRead != bytesPerMeasurement)
                    {
                        t = mySerialPort.Read(dataIn, bytesRead, bytesPerMeasurement - bytesRead);
                        bytesRead += t;
                    }
                    //convert them into hex string
                    StringBuilder s = new StringBuilder();
                    foreach (Byte b in dataIn) { s.Append(b.ToString("X") + ","); }
                    var line = s.ToString();

                                            var lineString = string.Format("{0}  ----          {2}",
                                                      line,
                                                    mySerialPort.BytesToRead);
                    data.Append(lineString + "\r\n");//append a measurement to a huge Stringbuilder...Need a solution for this.

                    ////use delegate to change UI thread...
                    textBox.BeginInvoke(new MethodInvoker(delegate() { textBox.Text = line; }));

                    if (mySerialPort.BytesToRead <= 100) { Thread.Sleep(100); }
                }
            else{Thread.Sleep(100);}

            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.ToString());
            }
        }


    }

Answer 1:

这是不是做的好方法,它好得多的DataReceived事件检索工作。

基本上与串行端口有一个3阶段的过程,效果很好。

  • 从串口接收数据
  • 等到你有数据的相关区块
  • 解读数据

所以像

class DataCollector
{
    private readonly Action<List<byte>> _processMeasurement;
    private readonly string _port;
    private SerialPort _serialPort;
    private const int SizeOfMeasurement = 4;
    List<byte> Data = new List<byte>();

    public DataCollector(string port, Action<List<byte>> processMeasurement)
    {
        _processMeasurement = processMeasurement;
        _serialPort = new SerialPort(port);
        _serialPort.DataReceived +=SerialPortDataReceived;
    }

    private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        while(_serialPort.BytesToRead > 0)
        {
           var count = _serialPort.BytesToRead;
           var bytes = new byte[count];
           _serialPort.Read(bytes, 0, count);
           AddBytes(bytes);
        }
    }

    private void AddBytes(byte[] bytes)
    {
        Data.AddRange(bytes);
        while(Data.Count > SizeOfMeasurement)            
        {
            var measurementData = Data.GetRange(0, SizeOfMeasurement);
            Data.RemoveRange(0, SizeOfMeasurement);
            if (_processMeasurement != null) _processMeasurement(measurementData);
        }

    }
}

注:添加字节不断收集数据,直到你有足够的计算为一次测量,或者如果你突发数据,将其分解成单独的测量....这样你就可以得到1个字节一次,2下了, 1更下一个,并且它将然后采取一个把它变成一个测量。 大多数的,如果你的微发送它在突发的时候,它会在为一体的,但有时它会被分成2个。

那么什么地方可以做

var collector = new DataCollector("COM1", ProcessMeasurement);

  private void ProcessMeasurement(List<byte> bytes)
            {
                // this will get called for every measurement, so then
                // put stuff into a text box.... or do whatever
            }


Answer 2:

首先,考虑阅读在.NET中使用秒表和计时器 。 你可以打破任何性能问题与此并确切地告诉它你的代码部分导致了问题。

使用SerialPort.DataReceived事件来触发数据接收过程。

单独的接收处理和数据处理的过程。 存储你的数据第一,然后处理。

不要读循环编辑UI。



Answer 3:

我猜你应该做的事情是添加一个事件处理程序来处理输入数据:

mySerialPort.DataReceived += new SerialDataReceivedEventHandler(mySerialPort_DataReceived);

这消除了需要运行一个单独的线程来你听每个串口。 此外,每个DataReceived处理程序将被称为精确当有数据可用,如有必要处理该数据,则产生到应用程序/操作系统将只消耗尽可能多的CPU时间。

如果不解决CPU占用问题,这意味着你做太多的处理。 但是,除非你有一些非常快的串行端口,我不能想象你到了那里会造成问题的代码。



文章来源: Serial Port Polling and Data handling