当读取刚刚打开的SerialPort时,只读取一个字节

本文关键字:读取 一个 字节 SerialPort | 更新日期: 2023-09-27 18:12:30

奇怪的问题

当我用SerialPort.Read()从com_port读取时,如果数据到达,在第一次调用时只读取一个字节,忽略count参数和超时内可用的字节数。所有进一步的读数都没问题,只有第一个有问题

使用SerialPort.DiscardInBuffer()或关闭/打开(重新打开)comport将再次导致第一次读取的问题。

下面是一些代码:
var port = new SerialPort();
port.PortName = "com2";
port.BaudRate = 9600;
port.WriteTimeout = 1000;
port.ReadTimeout = 1000;
port.Open();
// ... send some data first
var read = new byte[10];
if (port.Read(read, 0, read.Length) != read.Length)
{
    // always here at first reading no matter what
}
// ... send some data again
if (port.Read(read, 0, read.Length) != read.Length)
{
    // not here anymore (unless error)
}

当调用Read()时,如果指定的数据量已经可以读取,则不会出现问题。


一些解释。

Read()为同步读取。当接收到指定的数据量或超时时,它将返回。看起来,TimeoutException只会在接收到零字节时抛出。如果在读取请求的数据量之前超时,函数将返回已读取的字节数。因此,必须将返回值与请求值进行比较,以查看读取是否正常。

但是第一次调用有一个问题:

如果在超时期间到达0字节,则第一次调用正确地等待超时并触发TimeoutException。如果至少有1个字节已经到达,则函数立即结束,忽略超时和请求的字节数。

我是这样看的。我错了吗?我该怎么办?


更多的测试。插入Thread.Sleep()以确保在调用Read()时所有数据可用,将使问题消失。

逻辑上,让我们只为第一个调用添加sleep。耶。什么? ?问题现在出现在第二次调用仅第二次调用时。换句话说,问题出现在第一次读取()时,它将没有所有可用的数据,而只有一次

当读取刚刚打开的SerialPort时,只读取一个字节

因为在读取的时候,其他字节还没有到达,它将只读取一个字节,因为队列中只有一个字节。因此,如果至少有一个字节存在,它将不会等待所需的字节数,因为超时已经发生,但它不会抛出异常。如果没有,它将抛出超时异常。因此,您应该尝试读取,直到读取所需的字节数为止(在您的示例中为10个字节)。您可以尝试这样做:

int count = 0;
var read = new byte[10];
while ((count += port.Read(read, count, read.Length - count)) != read.Length) ;

但是如果超时发生了,也许这可以加强代码:

int count = 0;
var read = new byte[10];
while (count < read.Length)
{
    try
    {
        count += port.Read(read, count, read.Length - count);
    }
    catch (TimeoutException te)
    {
        //maybe increase ReadTimeout or something, use exponential backoff, your call
    }
}

我找到了我的解决方案,希望这对我有帮助:

ireadCount = serialPort.Read(readBuffer, 0, serialPort.ReadBufferSize);
Thread.Sleep(1);//This can be removed, just use it in case need time to complete the reception.
ireadCount = serialPort.Read(readBuffer, 1, serialPort.ReadBufferSize-1);
ireadCount +=1;

这样我就可以获得外部设备的整个响应,而不会丢失第一个字节。

Regards.——

处理这个问题有几种方法。如果你期望从你发送的命令中得到回复,你应该在调用serialPort.Write()之后至少休眠250毫秒,然后再调用serilPort.Read()。或者,如果您知道设备要发送回多少字节,则可以使用serialPort。BytesToRead属性延迟读取,直到您期望的字节数可用为止。如果您正在使用DataReceived Event,则可以设置serialPort。ReceivedBytesThreshold(默认为1)用于防止在预期的字节数可用之前引发事件。请记住,serialPort。方法不能保证返回所请求的字节数。这就是为什么要使用serialPort。Read方法返回一个整数,该整数是实际读取的字节数。