【问题标题】:How to read from serial device in C++如何在 C++ 中从串行设备读取
【发布时间】:2016-01-17 18:44:06
【问题描述】:

我正试图弄清楚我应该如何在 Linux C++ 中使用串行通信读取/写入我的 Arduino。目前我正在尝试从我的 Arudino 读取我“触发”的回复

echo "g" > /dev/ttyACM0"

我尝试使用以下命令在终端中查看我的 Arduino 的响应:

tail -f /dev/ttyACM0

这是正常工作的。现在我想在 C++ 应用程序中做同样的事情。所以我做了这个测试

void testSerialComm()
{

    std::string port = "/dev/ttyACM0";
    int device = open(port.c_str(), O_RDWR | O_NOCTTY | O_SYNC);

    std::string response;
    char buffer[64];

    do
    {
        int n = read(device, buffer, sizeof buffer);

        if (n > 0) {
            response += std::string(buffer);
            std::cout << buffer;
        }

    } while (buffer[0] != 'X'); // 'X' means end of transmission

    std::cout << "Response is: " << std::endl;
    std::cout << response << std::endl;

    close(device);

}

在几条“消息”之后,传输变得有点混乱。我的测试应用程序以随机​​顺序写入响应字符,但有些地方不对。我尝试通过以下命令配置 /dev/ttyACM0 设备:

stty -F /dev/ttyUSB0 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

没有骰子。有人可以帮助我了解如何在 C++ 中与我的 Arduino 进行通信吗?

【问题讨论】:

  • ftell() 的结果是什么?
  • 我以前用过boost serial。快速简单。
  • 所以你应该对这个错误返回做出某种反应,检查errno到底出了什么问题。
  • 您无法在 tty 上搜索,这是您问题的很大一部分。而不是预先知道数据有多大,您必须继续阅读,直到到达数据的末尾。
  • 那么,你打算如何沿着字符设备寻找呢?这有点不可能

标签: c++ linux arduino


【解决方案1】:

所示代码打开/dev/ttyACM0,尝试查找此“文件”的末尾,并根据生成的文件位置分配一个老式的C 风格内存缓冲区。

这种方法的问题在于,您只能通过常规、普通、普通的文件进行查找。 /dev/ttyACM0 不是常规文件。这是一个设备。虽然有些设备是可搜索的,但这个不是。根据 cmets 的说法,这是您独立发现的。

串口设备是可读写的。它们是不可搜索的。在串行端口上没有“寻找”这样的东西。这没有任何意义。

要从串行端口读取,您只需读取它即可。操作系统确实维护了一个一定大小的内部缓冲区,因此如果已经通过串行端口接收到一些字符,则初始读取会将它们全部返回(前提是read() 缓冲区大小足够大)。例如,如果您传递一个 1024 个字符的缓冲区,并且已经从串行端口读取了 5 个字符,read() 将返回 5,以表明这一点。

如果没有读取任何字符,并且您将串口作为阻塞设备打开,read() 将至少阻塞直到从串口读取一个字符,然后返回。

因此,为了从串行端口读取数据,您所要做的就是从它读取数据,直到您决定已经读取了所有要读取的数据。你怎么决定呢?随你(由你决定。您可以决定只阅读,直到阅读换行符。或者,您可能决定只阅读固定的#n 字符数。这完全取决于您。

当然,如果硬件布置得当,并且您对串行端口设备进行了必要的安排以尊重串行端口控制引脚,并且根据您的配置,DCD 和/或 DSR 引脚会发出信号表明串行端口设备不再可用,您的read() 将立即返回 0,表示串行端口设备上的文件伪结束条件。这也是您需要实现必要的逻辑来处理的事情。

附:由于它们自己的内部缓冲算法,C 风格的 stdio 和 C++ 风格的iostreams 都不能很好地与字符设备配合使用。使用串行端口时,使用open(2)read(2)write(2)close(2) 更好。但以上所有内容仍然适用。

【讨论】:

  • 非常感谢!我自动认为我必须将设备作为文件读取。从您的回答中,我知道我不应该使用 fwrite 写入设备?你的意思是这个 (stackoverflow.com/questions/19722801/…) 帖子中的方法是一个糟糕的解决方案?
  • 使用缓冲类,如 C++ [io]fstream,在您确切知道期望的输入和输出的情况下很好。但是,在你必须准备好处理不同的可能性的情况下,当你必须准确地弄清楚你最终阅读的内容时,正如我所说的你应该使用 open()、read() 和 write(),实际的系统调用,因为 fstream 类引入的缓冲通常会阻碍。
  • 现在尝试在设备上使用“打开”和“读取”。我正在使用“tail -f /dev/ttyACM0”来查看 Arduino 回写的内容。然后,我的应用程序能够读取 Arduino 响应的前 2 个字符(仅此而已)。如果我关闭“tail”程序,我的应用程序不会读取任何字符?我将把我的问题更新到目前为止。
  • 一般情况下,一个串口只能同时读取一个进程。当多个进程打开端口时,从串行端口接收到的每个字符都会被其中一个进程随机读取。此外,由于每个进程通常会尽可能多地读取,通过缓冲,终止的进程可能仍然成功地从串行端口读取一些额外的输入,这些输入是在进程被终止之前读取的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 2018-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多