我正在尝试通过微控制器从传感器的多个串行端口读取数据。每个串口将接收超过2000个测量值(每个测量值7个字节,全部为十六进制)。而且他们同时开火。现在我正在从 4 个串行端口进行轮询。另外,我将每个测量值转换为字符串并将其附加到字符串构建器。当我完成接收数据时,它们将被输出到文件中。问题是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<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);
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
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)