串行端口轮询和数据处理

我试图从传感器到微控制器的几个串口读取。 每个串行端口将接收超过2000个测量值(每个测量值为7个字节,全部为hex)。 他们同时开枪。 现在我正在从4个串口进行轮询。 此外,我将每个测量值转换为String并将其附加到Stringbuilder。 当我完成接收数据后,它们将被输入到文件中。 问题是CPU消耗非常高,从80%到100%不等。

我浏览了一些文章并将Thread.Sleep(100)放在最后。 它可以在没有数据时减少CPU时间。 当BytesToRead小于100时,我还在每次轮询结束时放置Thread.Sleep。它只在某种程度上有所帮助。

有人可以提出一个解决方案来从串口轮询并处理我得到的数据吗? 也许每次我得到的东西附加都会导致问题?

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

这不是一个好方法,它可以更好地处理DataReceived事件。

基本上有串口,有一个3阶段的过程,运作良好。

  • 从串行端口接收数据
  • 等到你有相关的数据块
  • 解释数据

所以像

 class DataCollector { private readonly Action> _processMeasurement; private readonly string _port; private SerialPort _serialPort; private const int SizeOfMeasurement = 4; List Data = new List(); public DataCollector(string port, Action> 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 bytes) { // this will get called for every measurement, so then // put stuff into a text box.... or do whatever } 

首先考虑在.NET中阅读使用Stopwatches和Timers 。 您可以解决任何性能问题,并确切地告诉您代码的哪个部分导致了问题。

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

单独的接收过程和数据操作过程。 先存储您的数据然后处理。

不要从阅读循环编辑UI。

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

 mySerialPort.DataReceived += new SerialDataReceivedEventHandler(mySerialPort_DataReceived); 

这样就无需为您收听的每个串行端口运行单独的线程。 此外,当有可用数据时,将精确调用每个DataReceived处理程序,并且将仅消耗处理数据所需的CPU时间,然后产生应用程序/ OS。

如果这不能解决CPU使用问题,则意味着您正在进行过多处理。 但除非你有一些非常快的串口,否则我无法想象你在那里得到的代码会造成问题。