如何使用C语言在Linux中从串口读取数据?

11

我是在Linux环境下使用C语言进行串口编程的新手。我找到了一小段代码来向串口写入数据,现在我想在另一个终端中读取那个特定串口上写入的数据 - 我该如何做?

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

/*
 * 'open_port()' - Open serial port 1.
 *
 * Returns the file descriptor on success or -1 on error.
 */
int
open_port(void)
{
  int fd; /* File descriptor for the port */

  fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1)
  {
   /* Could not open the port. */
    perror("open_port: Unable to open /dev/ttyS0 - ");
  }
  else
    fcntl(fd, F_SETFL, 0);

  n = write(fd, "ATZ\r", 4);
  if (n < 0)
    fputs("write() of 4 bytes failed!\n", stderr);

  return (fd);
}

以上代码将在特定端口上写入数据。


请注意,write函数可能(理论上)返回3,表示成功写入4个字节中的3个。您可以决定将“短写”视为错误还是重试写入缓冲区的剩余部分。 - Jonathan Leffler
2个回答

10

理论上,你只需要打开相关端口进行读取,然后使用read()获取数据即可。

int
read_port(void)
{
    int fd = open("/dev/ttyS0", O_RDONLY | O_NOCTTY);
    if (fd == -1)
    {
        /* Could not open the port. */
        perror("open_port: Unable to open /dev/ttyS0 - ");
    }

    char buffer[32];
    int n = read(fd, buffer, sizeof(buffer));
    if (n < 0)
        fputs("read failed!\n", stderr);
    return (fd);
}

有一些区别;值得注意的是,读取需要一个缓冲区来存储数据。所示代码会丢弃第一个读取的消息。请注意,短读取仅表示在读取完成时请求的数据量比可用数据量少。它并不自动表示错误。想象一下命令行;某些命令可能只有一两个字符(ls),而其他命令可能非常复杂(find /some/where -name '*.pdf' -mtime -3 -print)。使用相同的缓冲区读取这两者并不是问题;一个read给出3个字符(包括换行符),另一个给出大约47个字符。


感谢@Jonathan的友善回复。但是,当我尝试在其他终端运行这段代码时,我遇到了读取失败的错误。为什么在我成功使用其他终端将数据写入端口时它不能读取数据呢?我实际上想要像套接字一样,在终端之间使用环回地址进行通信! - Amit Singh Tomar
那就是实践干扰理论的地方。要成功地从端口读取数据,必须连接到端口的设备可以帮助你写入数据以便读取。因此,你必须关注端口另一边的硬件;它会如何响应计算机写入的数据,并且它将如何写入数据以供计算机读取。 - Jonathan Leffler
真的 @Jonathan,我现在的方法是只有一个Linux盒子,然后尝试使用终端进行通信。在一个终端上,我正在尝试将数据写入端口,在另一个终端上尝试读取它,同样的方式开始学习Linux套接字编程。但现在看起来我还需要一些串行电缆和两台机器。无论如何,非常感谢您的帮助! - Amit Singh Tomar
1
大多数情况下,如果没有对端口进行配置-波特率、转换等,则无法很好地工作。 - Chris Stratton
@ChrisStratton:嗯...是的,你可能是对的。你很快就会涉及到大量特定于系统的代码。你绝对需要知道从哪里获取适当的设置才能正确地使用<termios.h>中的函数(其中至少有一些部分不是特定于系统的 - 但是如果你需要设置波特率,例如,你需要知道打开的串行设备的正确波特率设置是什么)。 - Jonathan Leffler

8
该程序对端口状态做出了很多假设。在实际应用中,您应该明确地进行所有重要设置。我认为学习基于POSIX的串行端口编程的最佳来源是“POSIX操作系统串行编程指南”。我在这里提供其镜像:https://www.cmrr.umn.edu/~strupp/serial.html

@n0rd:谢谢你提醒我。我已经在我的服务器上设置了一个镜像副本。 - datenwolf
@datenwolf: 主页面已经有了镜像,但所有子页面的链接似乎都失效了。我可以在这里找到内容:https://www.cmrr.umn.edu/~strupp/serial.html - Electron
@Electron:该文档没有子页面,只是一个很长的HTML文件。问题是目录中的链接包含文件名“serial.html”,而不是简单的内部文档锚点。我已经将HTML中的链接更改为这样的内部文档锚点。 - datenwolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接