我在一个示例应用程序中的 C# 串行端口上遇到了数据丢失问题,该应用程序从微控制器板接收非常非常高的数据速度(在 2000 个 18 字节数据包中每秒高达 36000 字节)。
我的波特率是 1.000.000,我使用
DataReceived
事件。我有一个模拟器来生成主要应用程序测试的数据。我将两个 COM 端口(COM1 -> COM2)与“虚拟串口驱动程序”软件配对。
收到数据包后,它们会保存到
*.CSV
文件中,但一些数据会丢失。
我的第一个也是重要的问题是数据丢失。
我的第二个问题是这种情况下的CPU使用性能(高达50%或60%)。
这是我的模拟器串口配置和数据生成器代码:
SerialPort serialPort = new SerialPort("COM1", 1000000, Parity.None, 8, StopBits.One);
serialPort.Handshake = Handshake.None;
serialPort.Open();
serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
byte[] packet = new byte[] { 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 78 };
ulong packetCount = 0;
while (packetCount < 600000);
{
byte[] timeBytes = BitConverter.GetBytes(packetCount);
packet[2] = timeBytes[0];
packet[3] = timeBytes[1];
packet[4] = timeBytes[2];
packet[5] = timeBytes[3];
Write(packet);
packetCount++;
}
在此代码中,数据包具有标头 {83, 84} 和页脚 {69, 78}
这是我的主应用程序中的串口配置:
SerialPort _serialPort = new SerialPort("COM2", 1000000, Parity.None, 8, StopBits.One);
_serialPort.Handshake = Handshake.None;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
_serialPort.ReadBufferSize = 100;
这是我主应用程序中的
dataReceived
事件:
private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int count = _serialPort.BytesToRead;
byte[] receivedTemp = new byte[count];
_serialPort.Read(receivedTemp, 0, count);
_totalReceived.AddRange(receivedTemp);
findPacket();
}
这是使用页眉和页脚查找数据包的
findPacket
函数:
int findPacket(int index = 0, bool headerFounded = false)
{
while (index + 1 < _totalReceived.Count)
{
if (_totalReceived[index] == 83 && _totalReceived[index + 1] == 84)
{
int headerIndex = index;
int packetLen = 14;
int footerIndex = findPacket(index + 2 + packetLen, true);
if (footerIndex > -1 && (packetLen == 0 || (footerIndex == headerIndex + packetLen + 2)))
{
List<byte> data = totalReceived.GetRange(headerIndex + 2, footerIndex - (headerIndex + 2));
totalReceived.RemoveRange(headerIndex, footerIndex + 2 - headerIndex);
if (headerIndex > 0 && !headerFounded)
totalReceived.RemoveRange(0, headerIndex);
calcPacket(data);
continue;
}
else if (footerIndex != -1)
{
index++;
continue;
}
break;
}
if (headerFounded && totalReceived[index] == 69 && totalReceived[index + 1] == 78)
return index;
index++;
}
return -1;
}
问题是:当模拟器数据生成器启动时,
findPacket
非常非常忙,并且我的主应用程序中的所有其他异步功能(例如主 UI 和 CSV 编写器以及在线图表抽屉等)都无法工作并被锁定。
您可以在不使用递归函数的情况下完成此操作。递归函数会增加系统使用的资源。这种情况下,可能调用次数过多,导致时间错误 你可以这样做:
async void findPacket3()
{
byte[] header = new byte[] { 83, 84 };
byte[] footer = new byte[] { 69, 78 };
int maxLength = header.Length + footer.Length;
int index = 0;
int headerIndex = -1;
int footerIndex = -1;
while (!_canceltoken.IsCancellationRequested)
{
await Task.Delay(5);
while (index < totalRecieved.Count)
{
if (index + (header.Length - 1) < totalRecieved.Count && totalRecieved[index] == header[0] && totalRecieved[index + 1] == header[1])
{
headerIndex = index;
int packetLen = 0; // findPacketLen(index);
index += header.Length + packetLen;
continue;
}
if (headerIndex > -1 && index + (footer.Length - 1) < totalRecieved.Count && totalRecieved[index] == footer[0] && totalRecieved[index + 1] == footer[1])
{
footerIndex = index;
List<byte> data = totalRecieved.GetRange(headerIndex + header.Length, footerIndex - (headerIndex + header.Length));
calcPacket(data);
headerIndex = -1;
}
index++;
}
if (footerIndex > -1)
{
totalRecieved.RemoveRange(0, footerIndex + footer.Length);
footerIndex = -1;
index = 0;
headerIndex = -1;
}
}
}
还有,为了避免数据丢失,最好设置一下
_serialPort.ReadBufferSize = 4096;