我正在实现一个 C# 应用程序,它使用 USB 串行适配器(FTDI FT232H)以高波特率(8 MegaBaud)从微控制器读取二进制数据。问题是当流包含 0x1A 时,有时会在这个字节之后丢失一大块数据(数千字节)。
我在论坛上发现 0x1A 是一个特殊字符 (EOFCHAR),Windows 对此进行了特殊处理。但是,这种反编译SerialStream
和更改EOFCHAR
为另一个字节值的解决方案对我没有帮助,我需要使用整个字节范围(0..255)。
我创建了一个小型测试应用程序来重现我的问题,重复发送相同的字节,使用连接到同一台计算机的 2 个串行适配器和连接到 FT232H-RX 的 FT232R-TX
using System;
using System.IO.Ports;
using System.Collections.Generic;
using System.Text;
namespace SerialPort_0x1A_Loss_Test
{
class Program
{
static void Main(string[] args)
{
const byte BYTE_FILL = 0x1A; // 0x1A is EOFCHAR
const int BAUD_RATE = 3000000; // 3 MegaBaud
const int BUFF_SIZE = 1000000;
SerialPort sp1_FT232R =
new SerialPort("COM3", BAUD_RATE, Parity.None, 8, StopBits.One);
SerialPort sp2_FT232H =
new SerialPort("COM6", BAUD_RATE, Parity.None, 8, StopBits.One);
sp1_FT232R.Encoding = Encoding.GetEncoding(1252);
sp1_FT232R.WriteBufferSize = 20000000;
sp1_FT232R.Open();
sp2_FT232H.Encoding = Encoding.GetEncoding(1252);
sp2_FT232H.ReadBufferSize = 20000000;
sp2_FT232H.ReceivedBytesThreshold = 20000000;
sp2_FT232H.Open();
byte[] bufferTx = new byte[BUFF_SIZE];
for (int i = 0; i < BUFF_SIZE; i++)
{
bufferTx[i] = BYTE_FILL;
}
Console.WriteLine("Sending ...");
sp1_FT232R.Write(bufferTx, 0, BUFF_SIZE);
Console.WriteLine("Sending finished. " +
"Press a key to view status, ESC to exit.");
// Receiving maybe not yet finished,
// query the status with a keypress
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
Console.WriteLine("TOTAL RX = " + sp2_FT232H.BytesToRead);
}
// A second test, using .Read() call
// This will be executed after pressing ESC for the previous test
int totalRX_Read_Call = 0;
var listBufferRx = new List<byte>();
int btr; // BytesToRead
while ( (btr = sp2_FT232H.BytesToRead) > 0)
{
var bufferRx = new byte[btr];
totalRX_Read_Call += sp2_FT232H.Read(bufferRx, 0, btr);
listBufferRx.AddRange(bufferRx);
Console.WriteLine("totalRX_Read_Call = " + totalRX_Read_Call +
"; listBufferRx.Count = " + listBufferRx.Count);
}
Console.ReadKey();
sp1_FT232R.Close();
sp2_FT232H.Close();
}
}
}
测试结果(所有测试的 BUFF_SIZE = 1000000):
1. BYTE_FILL = 0x55; BAUD_RATE = 3000000; TOTAL RX = 1000000 ( no loss)
2. BYTE_FILL = 0x1A; BAUD_RATE = 3000000; TOTAL RX = 333529 (66% loss)
3. BYTE_FILL = 0x1A; BAUD_RATE = 2000000; TOTAL RX = 627222 (37% loss)
4. BYTE_FILL = 0x1A; BAUD_RATE = 1000000; TOTAL RX = 1000000 ( no loss)
此外,对于 2、3、4 等测试,CPU 上的负载(4 GHz 的 i7-4770k)很高(超过 30%),但测试 1 的负载很低(3%)。对于测试 1,我尝试了所有其他测试一个字节的模式(0x00..0x19,0x1B..0xFF)并且没有丢失。
您知道是否有解决方案吗?非常感谢!