【问题标题】:select() does not seem to work on TTYselect() 似乎不适用于 TTY
【发布时间】:2012-08-16 12:20:42
【问题描述】:

我目前正在编写一个程序,该程序需要通过 UART 接口与 AT 接口进行通信(操作系统是 Linux)。但我在文件描述符上使用select() 时遇到问题。由于某种原因,select 不认为文件描述符已准备好读取,但为了缩小问题范围,我使用了以下程序。

int main()
{
    char buffer[BSIZE];
    fd_set rfds;
    int ret;
    struct termios cnf;
    struct timeval tv;

    fd = open("/dev/ttyO1", O_RDWR);
    // Have also tried to set fd = 0 for stdin, as a reference
    signal(SIGINT, sig_handler);
    tcgetattr(fd, &cnf);
    old = cnf;
    cfmakeraw(&cnf);
    tcsetattr(fd, TCSANOW, &cnf);
    while (1) {
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
        write(fd, "AT\r", 3);
        ret = select(fd+1, &rfds, NULL, NULL, &tv);
        printf("ret = %d\n", ret);
        if (ret < 0) {
            perror("select()");
        }
        else {
            ret = read(fd, buffer, BSIZE-1);
            buffer[ret] = '\0';
            printf("read: \"%s\"\n", buffer);
        }
    }
    return 0;
}

运行看起来像这样

    root@linux:~# ./stuff
    ret = 0
    read: "AT
    OK
    "

这表明select认为没有数据,但是在尝试读取时有数据。这对我来说似乎很奇怪。另外,我尝试将 tty 与 stdin 交换,效果很好。

代码正在德州仪器 EZSDK PSP 内核上运行,但这应该不是问题。此外,stty 设置如下所示

    root@linux:~# stty -aF /dev/ttyO1
    speed 9600 baud; rows 24; columns 80;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
    eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
    lnext = ^V; flush = ^O; min = 1; time = 0;
    -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
    -iuclc -ixany -imaxbel
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
    echoctl echoke

我是否错过了open() 的重要标志?或者可能需要使用termios 设置一些设置?这种方法是否需要一些特殊的硬件

编辑: 我在尝试运行/dev/ttyUSB0 程序时遇到了同样的问题,这也恰好是一个 AT 接口。在我看来,它与tty 相关。

将 fd 更改为我实际使用并想知道的内容。

【问题讨论】:

  • 实际上,除了代码中的一些不一致(fd vs 0,以及在标准输入上完成的编写,这不应该工作)之外,它应该可以工作,而且很可能会工作。您是否尝试过像这样运行它:echo -ne 'AT\r' |./stuff?不过,它应该可以在真正的 tty 上运行(假设可以从中读取一些内容)。
  • 是的,这只是一个测试应用程序(事实证明它确实可以写入标准输入:D)。我试过在/dev/ttyO1 上运行microcom,效果很好,阅读和写作也很好。唯一的问题是select() 似乎对传入的数据没有反应。我的猜测是缺少一些 termios 设置。
  • 哦,写入标准输入有效,您只是无法阅读您写入的内容。

标签: c linux embedded serial-port


【解决方案1】:

你没有将串口的文件描述符添加到fd set。

换行:

FD_SET(0, &rfds);

到:

FD_SET(fd, &rfds);

如果您需要 fd 集合中的零,或者添加以下行。

FD_SET(fd, &rfds);

【讨论】:

  • 哎哟!我真的很想念那个。那解决了!非常感谢:)
【解决方案2】:

我认为应该是 /dev/ttyS1 而不是 /dev/tty01。您正在尝试在恰好连接到嵌入式板上的 UART 的 VT(虚拟终端)上进行选择,但这不是一回事,

【讨论】:

  • 当尝试打开/dev/ttyS1 或任何其他ttyS* 时,termios 调用不起作用(返回错误)。而且我不能在任何ttyS* 上使用microcom。所以我很有信心它应该是/dev/ttyO1。有什么地方可以让我详细了解虚拟终端和 ttys 之间的区别吗?
  • 这是一个“O”(字母 O)而不是 0(零)。用于 TI OMAP 的 Linux 内核 - 并且可能通过扩展一些其他衍生设备(例如 Sitara 系列设备)具有名为 /dev/ttyO1 及更高版本的硬件串行端口。 (我认为为了理智起见,它们是基于“1”的)
  • @Kotte 我明白了。那我的回答就没有意义了。对不起。
猜你喜欢
  • 2020-04-04
  • 2023-04-06
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多