我正试图通过微控制器从传感器的几个串行端口读取。每个串行端口将接收2000多个测量值(每个测量值为7字节,全部为十六进制)。他们同时开火。现在我正在从4个串行端口轮询。此外,我将每个测量值转换为String并将其附加到Stringbuilder中。当我完成接收数据时,它们将被输出到一个文件中。问题是CPU消耗非常高,从80%到100%不等。
我浏览了一些文章,把Thread.Sleep(100)放在最后。当没有数据传入时,它减少了CPU时间。我也把线程。当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 + "rn");//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事件。
基本上,对于串行端口,有三个阶段的过程可以很好地工作。
- 从串口接收数据
- 等待你有一个相关的数据块
- 解释数据
所以像
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);
}
}
}
注意:Add Bytes继续收集数据,直到你有足够的计数作为一个测量,或者如果你得到一个数据的爆发,将其分成单独的测量....所以你可以一次得到1个字节,下一个2个,下一个1个,然后它会把它变成一个测量值。大多数情况下,如果你的微信发送了一个突发事件,它会作为一个出现,但有时它会被分成两个。
那么你可以在某个地方做
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
}
首先考虑阅读。net中使用秒表和计时器。您可以用它分解任何性能问题,并准确地指出是代码的哪一部分导致了问题。
使用串口。DataReceived事件,触发数据接收过程。
分离接收过程和数据操作过程。先存储数据再处理。
不要在阅读循环中编辑UI
我猜你应该做的是添加一个事件处理程序来处理传入的数据:
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(mySerialPort_DataReceived);
这消除了为侦听的每个串行端口运行单独线程的需要。此外,每个DataReceived处理程序将在有数据可用时精确调用,并且只消耗处理数据所需的CPU时间,然后向应用程序/操作系统屈服。
如果这不能解决CPU使用问题,这意味着你做了太多的处理。但是,除非你有一些非常快的串行端口,否则我无法想象你在那里的代码会造成问题。