我有一些代码需要从串行设备读取。它是由速率 r
调用的轮询函数。
设备以 \r\n
分隔的行形式输出数据,速度很快,大约 100Hz。每当我轮询时,我都想读取整个串行缓冲区。我发现这很难用 boost::asio 来做,因为它似乎没有为我提供 available()
函数。
我尝试的方法之一是使用 read_until()
但它没有解决我的问题,因为在 \r\n
之后缓冲区中可能有更新的数据> read_until()
停止于。
我在读取缓冲区后尝试了 consume()
,但在我知道我已从设备读取最新数据之前,这仍然是一项 hack 工作。
有人对这个问题有建议吗?
最佳答案
由于串行端口是作为流而不是随机访问句柄读取的,因此必须按照接收数据的顺序读取数据。鉴于此行为,这里有一些获取最新数据的选项:
- 从流中读取,直到读取操作因超时而失败。虽然 Boost.Asio 既不提供非阻塞同步读取也不提供串行 I/O 对象的超时读取,但可以使用异步读取和计时器来实现这一行为。 Boost.Asio 提供了一个超时集合examples .由于“
\r\n
”字符序列用于数据边界,请考虑使用async_read_until()
尊重数据边界,而不必在应用程序代码中引入边界处理。如果入口速率大于消耗速率,则超时可能不确定。 - 使用串口的
native_handle()
使用系统特定的调用来确定可用于读取的字节数。然后,制定一个读取策略,使用可用字节数来确定何时停止读取。请注意,可用字节数可能不会直接落在数据边界上。因此,应用程序需要处理碎片。例如,可以使用超时async_read_until()
。但是,一旦消耗了先前已知的可用字节数,就可以显式停止异步调用链。这为异步调用链提供了一个确定性的结束,即使入口速率超过消费速率。查阅系统文档以确定如何查询准备读取的可用字节,但通常是ioctl(..., FIONREAD, ...)
在 Linux 上,和ClearCommError()
在 Windows 上。 - 将使用数据与串行端口和查询最近接收到的数据分离。通过职责分离,消费者线程将通过
async_read_until()
调用链不断从串行端口读取数据,并保留最近读取的数据。根据访问最新数据的方式,可能需要同步机制(如互斥锁)来避免竞争条件。从串行端口读取后无需锁定的一种替代方法是使用 future / promise ,并将实现 promise 的操作发布到运行async_read_until()
循环的同一链中。 - 如果数据写入频率足够高,可以接受在轮询中等待完整样本,那么可以 flush the serial port's receive buffer ,导致所有数据被丢弃。一旦被丢弃,就可以从串行端口读取,等待写入发生,从而产生最新的数据。由于刷新缓冲区可能会丢弃样本的一部分,因此可能需要读取第二个数据边界以保证已读取完整的样本。
关于c++ - 使用boost asio从串口读取最新数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27678647/