从串口读取数据失败。

6

我有以下C程序:

#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

int main()
{
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(fd < 0)
    {
        perror("Could not open device");
    }
    printf("Device opened\n");

    struct termios options;
    tcgetattr(fd, &options);
    cfmakeraw(&options);
    cfsetispeed(&options, B19200);
    cfsetospeed(&options, B19200);
    tcsetattr(fd, TCSANOW, &options);

    char txpacket[] = {0x23, 0x06, 0x00, 0x00, 0xdd, 0xf9};
    ssize_t written = write(fd, txpacket, sizeof(txpacket));
    printf("Written %d bytes\n", written);

    printf("Starting to wait for target to respond\n");
    while(1)
    {
        fd_set readset;
        FD_ZERO(&readset);
        FD_SET(fd, &readset);
        int nCount = select(fd + 1, &readset, NULL, NULL, NULL);
        if(nCount > 0)
        {
            if(FD_ISSET(fd, &readset))
            {
                int i;
                char buffer[128];
                ssize_t bytesread = read(fd, buffer, sizeof(buffer));
                printf("Received %d bytes\n", bytesread);
                for(i = 0; i < bytesread; i++)
                {
                    printf("  %02x", buffer[i]);
                }
            }
        }
    }
}

该程序打开串口设备/dev/ttyS0,向其写入一系列数据并开始等待响应。输出如下所示:
Device opened
Written 6 bytes
Starting to wait for target to respond
Received 0 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
...

应用程序消耗了100%的CPU。尽管目标硬件实际上传输数据,但我无法接收任何数据。

问题出在哪里?

2个回答

8

read() 返回 0 表示文件结束。如果发生这种情况,您应该检查并跳出循环。

至于导致这种情况的原因 - 在串行端口上的文件结束表示它已检测到挂起,这意味着 DCD 线已经断开。

如果您的设备没有正确设置 modem 控制线,则可以在 options.c_cflag 中设置 CLOCAL 标志以忽略 modem 控制线。


谢谢!那确实是导致问题的原因。 - anorm
该死,没看到CLOCAL这个东西! - shodanex
遇到了同样的问题,感谢您的提示。我没有意识到cfmakeraw没有看到那两个明显的标志。 - RishiD
这里有一个旧的帖子,我知道,但我现在自己也面临着这个问题 - 如果read()返回0,推荐采取什么行动?您需要刷新和关闭端口并重新打开吗?谢谢。 - Fra
1
@Fra:open() 返回的新文件描述符不一定与您刚关闭的那个号码相同,因此,如果旧文件描述符在其他地方记录(例如在 fd_set 中),则需要将其删除并用新打开的一个替换它。 - caf
显示剩余7条评论

1

你应该尝试不使用O_NONBLOCK标志。在原始模式下,如果c_cc [VMIN]c_cc [VTIME]的设置为0,则串口将按照以下方式运行(根据man cfmakeraw):

如果有数据可用,则读取立即返回,返回可用字节数或请求的字节数中较小的一个。如果没有数据可用,则读取返回0

所以你应该尝试:

options->c_cc[VMIN]=1;

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