【问题标题】:Reading the latest data from serial port using boost asio使用boost asio从串口读取最新数据
【发布时间】:2015-02-25 00:51:48
【问题描述】:

我有一些需要从串行设备读取的代码。它是一个轮询函数,以r 的速率调用。

设备以\r\n 分隔的行中输出数据,速度很快,大约为 100Hz。每当我轮询时,我都想读取整个串行缓冲区。我发现 boost::asio 很难做到这一点,因为它似乎没有为我提供 available() 函数。

我尝试的一种方法是使用read_until(),但这并不能解决我的问题,因为在read_until() 停止的\r\n 之后,缓冲区中可能有更新的数据。

我在读取缓冲区后尝试了consume(),但这仍然是一项黑客工作,直到我知道我已经从设备读取了最新数据。

有人对这个问题有什么建议吗?

【问题讨论】:

  • 这是你必须照顾好自己的事情,boost::asio 并不认为\r\n 有那么特别。使用缓冲区。
  • @HansPassant 当然,我确实考虑过这一点,并使用了 read_until() 函数来处理它。但我在想的是,如果我使用 read_until(),它将从缓冲区堆栈的顶部读取。我想要最新的数据,因此将位于堆栈的底部。如何反转缓冲区?
  • 在缓冲区清空之前不要补充缓冲区。串口驱动已经有接收缓冲区了。

标签: c++ boost serial-port boost-asio


【解决方案1】:

由于串行端口是作为流而不是随机访问句柄读取的,因此必须按照接收数据的顺序读取数据。鉴于这种行为,以下是获取最新数据的几个选项:

  • 从流中读取,直到读取操作因超时而失败。虽然 Boost.Asio 既不提供非阻塞同步读取,也不提供串行 I/O 对象的超时读取,但可以使用异步读取和计时器来实现这一行为。 Boost.Asio 提供了一个超时集合examples。由于“\r\n”字符序列用于数据边界,请考虑使用async_read_until() 来尊重数据边界,而不必在应用程序代码中引入边界处理。如果进入率大于消耗率,则超时可能不是确定性的。
  • 将串行端口的native_handle() 与系统特定调用一起使用,以确定可供读取的字节数。然后,制定一个读取策略,该策略使用可用的字节数来确定何时停止读取。请注意,可用字节数可能不会直接落在数据边界上。因此,应用程序将需要处理碎片。例如,可以async_read_until() 超时。但是,一旦使用了先前已知的可用字节数,就可以显式停止异步调用链。这为异步调用链提供了一个确定性的结束,即使进入率超过了消耗率。请查阅系统文档以确定如何查询可供读取的可用字节,但通常在 Linux 上为 ioctl(..., FIONREAD, ...),在 Windows 上为 ClearCommError()
  • 将消费数据与串行端口分离并查询最近收到的数据。在职责分离的情况下,消费者线程将通过async_read_until() 调用链不断地从串行端口读取数据,并保存最近读取的数据。根据访问最新数据的方式,可能需要诸如互斥锁之类的同步机制来避免竞争条件。一种无需在读取串行端口后锁定的替代方法是使用未来/承诺,并将履行承诺的操作发布到运行async_read_until() 循环的同一链中。
  • 如果数据以足够高的频率写入,在轮询中等待完整样本是可以接受的,那么可以flush the serial port's receive buffer,导致所有数据被丢弃。一旦被丢弃,就可以从串行端口读取,等待写入发生,从而产生最新的数据。由于刷新缓冲区可能会丢弃部分样本,因此可能需要读取到第二个数据边界以确保已读取完整的样本。

【讨论】:

    猜你喜欢
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 2015-06-24
    相关资源
    最近更新 更多