C# - SerialPort.read() 速度问题
C# - SerialPort.read() speed issue
我的代码旨在从串行设备获取数据并将其内容打印到 MS Forms 应用程序。我使用的 IDE 是 Visual Studio 2019 - 社区。
设备确实发送了可变大小的数据包。首先,我必须解码数据包“header”以获得进一步处理的关键信息,即第一个数据包通道和数据包长度。
由于数据包既不包含行结束符,也没有结尾处的固定字符,因此函数SerialPort.ReadTo()
和SerialPort.ReadLine()
没有用。因此只能使用SerialPort.Read(buf,offset,count)
由于发送相当大的数据包(512 字节)确实需要时间,我实现了一个计算所需等待时间的函数,定义为 (1000ms/baud-rate*(8*byte-count))+100ms
在测试时,我遇到了延迟,远远超过了预期的等待时间,因此为函数的不同部分实现了一个测量函数。
在正常情况下(有期望的等待时间)我除了日志到控制台是这样的:
Load Header(+122ms) Load Data (+326ms) Transform (+3ms)
但它只适用于一些可变数量的记录,通常是 10,之后,执行时间会更糟:
Load Header(+972ms) Load Data (+990ms) Transform (+2ms)
这里可以看到完整的函数:
private void decodeWriteResponse(int identifier, object sender, SerialDataReceivedEventArgs e)
{
/* MEASURE TIME NOW */
long start = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
var serialPort = (SerialPort)sender; //new serial port object
int delay = ComPort.getWaitTime(7); //Returns the wait time (1s/baudrate * bytecount *8) +100ms Additional
Task.Delay(delay).Wait(); //wait until the device has send all its data!
byte[] databytes = new byte[6]; //new buffer
try
{
serialPort.Read(databytes, 0, 6); //read the data
}
catch (Exception) { };
/* MEASURE TIME NOW */
long between_header = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
/* Read the Data from Port */
int rec_len = databytes[1] | databytes[2] << 8; //Extract number of channels
int start_chnl = databytes[3] | databytes[4] << 8; //Extract the first channel
delay = ComPort.getWaitTime(rec_len+7); //get wait time
Task.Delay(delay).Wait(); //wait until the device has send all its data!
byte[] buf = new byte[rec_len-3]; //new buffer
try
{
serialPort.Read(buf, 0, rec_len-3); //read the data
}
catch (Exception) {}
/* MEASURE TIME NOW */
long after_load = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
/* Now perform spectrum analysis */
decodeSpectrumData(buf, start_chnl, rec_len-4);
/*MEASURE TIME NOW */
long end = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
Form.rtxtDataArea.AppendText("Load Header(+" + (between_header - start).ToString() + "ms) Load Data (+" + (after_load - between_header).ToString() + "ms) Transform (+" + (end - after_load) + "ms)\n");
/*Update the Write handler */
loadSpectrumHandler(1);
}
什么可能导致此问题?
我已经在 Visual Studio 中用“debug”测试过它,并作为“Release”独立测试过,但没有区别。
与其试图计算消息到达端口需要多长时间,为什么不循环读取数据直到你拥有所有数据?例如,读取 header 并计算消息大小。然后读取该字节数。例如:
// See if there are at least enough bytes for a header
if (serialPort.BytesToRead >= 6) {
byte[] databytes = new byte[6];
serialPort.Read(databytes, 0, 6);
// Parse the header - you have to create this function
int calculatedMsgSize = ValidateHeader(databytes);
byte [] msg = new byte[calculatedMsgSize];
int bytesRead = 0;
while (bytesRead < calculatedMsgSize) {
if (serialPort.BytesToRead) {
bytesRead += serialPort.Read(msg, bytesRead,
Math.min(calculatedMsgSize - bytesRead, serialPort.BytesToRead));
}
}
// You should now have a complete message
HandleMsg(msg);
}
我的代码旨在从串行设备获取数据并将其内容打印到 MS Forms 应用程序。我使用的 IDE 是 Visual Studio 2019 - 社区。
设备确实发送了可变大小的数据包。首先,我必须解码数据包“header”以获得进一步处理的关键信息,即第一个数据包通道和数据包长度。
由于数据包既不包含行结束符,也没有结尾处的固定字符,因此函数SerialPort.ReadTo()
和SerialPort.ReadLine()
没有用。因此只能使用SerialPort.Read(buf,offset,count)
由于发送相当大的数据包(512 字节)确实需要时间,我实现了一个计算所需等待时间的函数,定义为 (1000ms/baud-rate*(8*byte-count))+100ms
在测试时,我遇到了延迟,远远超过了预期的等待时间,因此为函数的不同部分实现了一个测量函数。
在正常情况下(有期望的等待时间)我除了日志到控制台是这样的:
Load Header(+122ms) Load Data (+326ms) Transform (+3ms)
但它只适用于一些可变数量的记录,通常是 10,之后,执行时间会更糟:
Load Header(+972ms) Load Data (+990ms) Transform (+2ms)
这里可以看到完整的函数:
private void decodeWriteResponse(int identifier, object sender, SerialDataReceivedEventArgs e)
{
/* MEASURE TIME NOW */
long start = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
var serialPort = (SerialPort)sender; //new serial port object
int delay = ComPort.getWaitTime(7); //Returns the wait time (1s/baudrate * bytecount *8) +100ms Additional
Task.Delay(delay).Wait(); //wait until the device has send all its data!
byte[] databytes = new byte[6]; //new buffer
try
{
serialPort.Read(databytes, 0, 6); //read the data
}
catch (Exception) { };
/* MEASURE TIME NOW */
long between_header = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
/* Read the Data from Port */
int rec_len = databytes[1] | databytes[2] << 8; //Extract number of channels
int start_chnl = databytes[3] | databytes[4] << 8; //Extract the first channel
delay = ComPort.getWaitTime(rec_len+7); //get wait time
Task.Delay(delay).Wait(); //wait until the device has send all its data!
byte[] buf = new byte[rec_len-3]; //new buffer
try
{
serialPort.Read(buf, 0, rec_len-3); //read the data
}
catch (Exception) {}
/* MEASURE TIME NOW */
long after_load = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
/* Now perform spectrum analysis */
decodeSpectrumData(buf, start_chnl, rec_len-4);
/*MEASURE TIME NOW */
long end = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
Form.rtxtDataArea.AppendText("Load Header(+" + (between_header - start).ToString() + "ms) Load Data (+" + (after_load - between_header).ToString() + "ms) Transform (+" + (end - after_load) + "ms)\n");
/*Update the Write handler */
loadSpectrumHandler(1);
}
什么可能导致此问题? 我已经在 Visual Studio 中用“debug”测试过它,并作为“Release”独立测试过,但没有区别。
与其试图计算消息到达端口需要多长时间,为什么不循环读取数据直到你拥有所有数据?例如,读取 header 并计算消息大小。然后读取该字节数。例如:
// See if there are at least enough bytes for a header
if (serialPort.BytesToRead >= 6) {
byte[] databytes = new byte[6];
serialPort.Read(databytes, 0, 6);
// Parse the header - you have to create this function
int calculatedMsgSize = ValidateHeader(databytes);
byte [] msg = new byte[calculatedMsgSize];
int bytesRead = 0;
while (bytesRead < calculatedMsgSize) {
if (serialPort.BytesToRead) {
bytesRead += serialPort.Read(msg, bytesRead,
Math.min(calculatedMsgSize - bytesRead, serialPort.BytesToRead));
}
}
// You should now have a complete message
HandleMsg(msg);
}