Linux - 串口读取返回 EAGAIN

10

我在读取串口数据时遇到了一些问题。我使用了以下代码实例,之前用过很多次都没有问题,但现在由于某些原因,我完全无法从串口读取任何数据。

我能够写入数据,接收端也正确接收到了数据,但是回复(已经正确发送)却无法接收(不,线缆都没问题;))

我用的代码打开串口如下:

fd = open("/dev/ttyUSB0", O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd == -1)
{
    Aviso("Unable to open port");
    return (fd);
}
else
{
    //Get the current options for the port...
    bzero(&options, sizeof(options)); /* clear struct for new port settings */
    tcgetattr(fd, &options);

    /*-- Set baud rate -------------------------------------------------------*/
    if (cfsetispeed(&options, SerialBaudInterp(BaudRate))==-1)
        perror("On cfsetispeed:");
    if (cfsetospeed(&options, SerialBaudInterp(BaudRate))==-1)
        perror("On cfsetospeed:");

    //Enable the receiver and set local mode...
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB; /* Parity disabled */
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;  /* Mask the character size bits */
    options.c_cflag |= SerialDataBitsInterp(8);           /* CS8 - Selects 8 data bits */
    options.c_cflag &= ~CRTSCTS;                            // disable hardware flow control
    options.c_iflag &= ~(IXON | IXOFF | IXANY);           // disable XON XOFF (for transmit and receive)
    options.c_cflag |= CRTSCTS;                         /* enable hardware flow control */
    
    options.c_cc[VMIN] = 0;     //min carachters to be read
    options.c_cc[VTIME] = 0;    //Time to wait for data (tenths of seconds)

    //Set the new options for the port...
    tcflush(fd, TCIFLUSH);
    if (tcsetattr(fd, TCSANOW, &options)==-1)
    {
        perror("On tcsetattr:");
    }

    PortOpen[ComPort] = fd;
}

return PortOpen[ComPort];

端口初始化后,我通过简单的写入命令向其写入一些内容...

int nc = write(hCom, txchar, n);

在这里,hCom是文件描述符(并且它没问题),这个方法可以正常工作。但是...当我之后进行读取操作时,会从errno返回一个“资源暂时不可用”的错误。

我尝试使用select来检测文件描述符是否有可读内容......但它总是超时!

我按如下方式读取数据:

ret = read(hCom, rxchar, n);

我总是收到 EAGAIN 错误,但不知道为什么。

更新:

硬件没问题!我可以看到串口上有入站数据,因为我做了一个调试电缆来在另一个终端上读取正在发生的事情。所以...

我知道非阻塞应该如何工作。我的问题是... 为什么什么都没有被读取!同样的设置在 Windows 上运行良好,所以所有硬件都正常..。

这让我抓狂!我敢肯定这是极其简单的问题!我甚至尝试去掉 O_NONBLOCK,看看什么时候会收到数据... 但没有任何反应...


我也遇到了同样的问题。我可以通过USB-RS232适配器电缆进行传输,但无法接收。我在另一台有RS232端口的Linux机器上尝试了一下,结果正常工作。我所做的唯一更改是从“/dev/ttyUSB0”更改为“/dev/ttyS0”。第一台计算机是Fedora,第二台是Debian。除此之外,我不知道还有什么其他原因。还有一件事。当我关闭串口程序并重新启动它时,我的程序会读取数据!这些数据是输入缓冲区中的数据,但我的程序不知道它。此外,gtkterm运行良好,因此硬件都没有问题。我的程序无法看到UART中断。这个Linux硬件抽象层相当麻烦。 - Don Lawrence
4个回答

11

阅读这篇文章

EAGAIN是指使用O_NONBLOCK进行非阻塞I/O操作时,没有立即可供读取的数据。


6
问题就在这里,虽然有点简洁。我猜更广泛的问题是,如果你没有准备好处理它的行为,为什么要指定O_NONBLOCK? - Andy Ross

2

首先需要检查串行终端设置。

使用命令- stty -F /dev/ttyUSB0 -a

检查是否选择了ctsrts作为-ctsrts,并使用stty实用程序进行其他必要的设置,然后就完成了。


0

看看我的代码示例,如果出现EAGAIN错误,你应该再次尝试读取:

...
options.c_cflag &= ~PARENB; 
options.c_iflag &= ~INPCK; 
...
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // input
options.c_oflag &= ~OPOST; // output
...
fd = open("/dev/ttyUSB0", O_RDWR | O_NDELY | O_NOCTTY);
fcntl(fd, F_SETFL, 0);
...
int nc = write(hCom, txchar, n);
msleep(500); // wait 500ms
fcntl(hCom, F_SETFL, FNDELAY); // don't block serial read
ret = read(hCom, rxchar, n);
if (ret > 0) {
    here had read n bytes or just partial data, read again if partial.
} 
if (ret < 0) {
    if (EAGAIN == errno) {
        not a real error, just read again.
    } else {
        oops, errors.
    }
}
...

空模拟电缆还是外置环回电缆?如果是后者,引脚分配是什么? - Test
刚刚把RS232端口的Tx和Rx焊接在一起,然后在另一台机器上通过超级终端从中读取。 - André Moreira
抱歉,你是否尝试将引脚#5也连接在一起,除了#2-#3和#3-#2之外?听起来在PC-PC情况下需要#5。 - Test
嗯,调试电缆好像没问题。其他的都完全匹配。我使用了盒子里附带的电缆来读取数据。有些可疑!errno显示EAGAIN的时候会出现“资源暂时不可用”,但是没有其他人打开串口!我打开了它,写入了数据,然后……我无法从中读取!难道读取被阻塞了吗…… - André Moreira
你可能想说的是 O_NDELAY 而不是 O_NDELY。 - azmeuk
显示剩余2条评论

0

EAGAINO_NONBLOCK一起使用时表示端口上没有接收到数据。请检查端口和电缆是否正常工作(使用minicom或其他已知良好的程序),并确保远程设备确实正在发送数据。


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