串行端口查询和数据处理 [英] Serial Port Polling and Data handling

查看:154
本文介绍了串行端口查询和数据处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



有人可以提出一个解决方案,从串行端口查询和处理,我得到的数据?也许追加每次我得到的东西会导致什么问题?



  //我用单独的线程所有传感器
私人无效SensorThread(的SerialPort mySerialPort,应INT bytesPerMeasurement,文本框文本框中StringBuilder的数据)
{
textBox.BeginInvoke(新MethodInvoker(委托(){textBox.Text =;}));

INT读取动作;
INT吨;
字节[] DATAIN;

,而(mySerialPort.IsOpen)
{

{
如果(mySerialPort.BytesToRead!= 0)
{
//试图读取的字节
的固定数量读取动作= 0;
T = 0;
DATAIN =新的字节[bytesPerMeasurement]
T = mySerialPort.Read(DATAIN,0,bytesPerMeasurement);
读取动作+ = T;
,而(读取动作= bytesPerMeasurement!)
{
T = mySerialPort.Read(DATAIN,读取动作,bytesPerMeasurement - 读取动作);
读取动作+ = T;
}
//转换他们到十六进制字符串
StringBuilder的S =新的StringBuilder();
的foreach(在DATAIN字节二){s.Append(b.ToString(X)+,); }
变种线= s.ToString();

线串VAR =的String.Format({0} ---- {2},
线,
mySerialPort.BytesToRead);
data.Append(线串+\r\\\
); //追加测量一个巨大的StringBuilder ...需要一个解决方案。

////使用委托来改变UI线程...
textBox.BeginInvoke(新MethodInvoker(委托(){textBox.Text =行;}));

如果(mySerialPort.BytesToRead&下; = 100){Thread.sleep代码(100); }
}
,否则{Thread.sleep代码(100);}

}
赶上(异常前)
{
//的MessageBox .Show(ex.ToString());
}
}


}


解决方案

这是不是做的好方法,它远不如在DataReceived事件检索工作。



港口有一个3阶段的过程,效果很好。




  • 从串行口接收数据

  • 等到你有数据

  • 的有关大块解读数据



所以像

 类DataCollector 
{
私人只读动作<名单<字节>> _processMeasurement;
私人只读字符串_port;
私人的SerialPort _serialPort;
私人const int的SizeOfMeasurement = 4;
名单,LT;字节>数据=新的List<位>();

公共DataCollector(串口,动作<名单,LT;字节>> processMeasurement)
{
_processMeasurement = processMeasurement;
_serialPort =新的SerialPort(端口);
_serialPort.DataReceived + = SerialPortDataReceived;
}

私人无效SerialPortDataReceived(对象发件人,SerialDataReceivedEventArgs E)
{
,而(_serialPort.BytesToRead大于0)
{
变种数= _serialPort.BytesToRead;
变种字节=新的字节[统计]
_serialPort.Read(字节,0,计数);
AddBytes(字节);
}
}

私人无效AddBytes(字节[]字节)
{
Data.AddRange(字节);
,而(Data.Count> SizeOfMeasurement)
{
VAR measurementData = Data.GetRange(0,SizeOfMeasurement);
Data.RemoveRange(0,SizeOfMeasurement);
如果(_processMeasurement!= NULL)_processMeasurement(measurementData);
}

}
}

请注意:添加字节不断收集数据,直到你有足够的计算为一次测量,或者如果你的数据一阵,它拆分成单独的测量....这样你就可以得到1个字节一次,2下了,另外1个接下来,它会再采取一种把它变成一个测量。大多数的,如果你的微发送它在突发的时候,它会在为一体的,但有时它会被分成2。



那么什么地方可以做

  VAR收集=新DataCollector(COM1,ProcessMeasurement); 

 私人无效ProcessMeasurement(列表<字节>字节)
{
//这将调用每一个测量,所以后来
//把东西到文本中... 。或做任何
}


I am trying to read from several serial ports from sensors through microcontrollers. Each serial port will receive more than 2000 measurements (each measurement is 7 bytes, all in hex). And they are firing at the same time. Right now I am polling from 4 serial ports. Also, I translate each measurement into String and append it to a Stringbuilder. When I finish receiving data, they will be ouput in to a file. The problem is the CPU consumption is very high, ranging from 80% to 100%.

I went though some articles and put Thread.Sleep(100) at the end. It reduces CPU time when there is no data coming. I also put Thread.Sleep at the end of each polling when the BytesToRead is smaller than 100. It only helps to a certain extent.

Can someone suggest a solution to poll from serial port and handle data that I get? Maybe appending every time I get something causes the problem?

//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());
            }
        }


    }

解决方案

this is not a good way to do it, it far better to work on the DataReceived event.

basically with serial ports there's a 3 stage process that works well.

  • Receiving the Data from the serial port
  • Waiting till you have a relevant chunk of data
  • Interpreting the data

so something like

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);
        }

    }
}

Note: Add Bytes keeps collecting data till you have enough to count as a measurement, or if you get a burst of data, splits it up into seperate measurements.... so you can get 1 byte one time, 2 the next, and 1 more the next, and it will then take that an turn it into a measurement. Most of the time if your micro sends it in a burst, it will come in as one, but sometimes it will get split into 2.

then somewhere you can do

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

and

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

这篇关于串行端口查询和数据处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆