关闭串口连接时程序卡住了

5

我正在使用PL2303驱动通过USB连接作为串行端口读取数据。当进行open并设置TTY选项和非阻塞时,它返回成功。但是,当我尝试关闭连接时,它会挂起。在这种情况下,它会读取 "�" 而不是字符。

我可以使用cutecom完美地连接到设备。这里是奇怪的部分:

  1. 如果我首先通过cutecom(一个串行监视器)连接到设备,那么我的程序每次连接和关闭都能够正常运行。它会按照我期望的读取字符。(没有 �)。
  2. 如果我断开并重新连接硬件,我的程序将再次挂起,直到我运行cutecom。

由于我使用cutecom之后它可以工作,这使我认为我在初始连接或连接设置中缺少了一些东西。以下是我用来连接的内容:

baud_rate = 38400;
fd =  open (device_path, O_RDONLY | O_NOCTTY );

在我的set_tty_options函数中:
struct termios tty_options;

memset (&tty_options, 0, sizeof(tty_options));
tcgetattr (fd, &tty_options);

cfsetispeed(&tty_options, baud_rate);                         // set baud rate
tty_options.c_cflag = (tty_options.c_cflag & ~CSIZE) | CS8;   // 8 bit msgs
tty_options.c_cflag |= (CLOCAL | CREAD);                      // enable reading

tty_options.c_cflag &= ~(PARENB | PARODD);                    // shut off parity
tty_options.c_cflag |= parity;
tty_options.c_cflag &= ~CSTOPB;
tty_options.c_cflag &= ~CRTSCTS;

if (tcsetattr (fd, TCSANOW, &tty_options) != 0) 
{
  printf("error %d from tcsetattr\n", errno);
  return TTY_ERROR;
}

set_blocking 函数中:
if (tcgetattr (fd, &tty) != 0)
{
  printf("error %d from tggetattr", errno);
  return FAILURE;
}

// 0 or 1 byte is enough to return from read
tty.c_cc[VMIN]  = should_block ? 1 : 0; 
tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

if (tcsetattr (fd, TCSANOW, &tty) != 0) 
{
  printf("error %d setting term attributes", errno);
  return FAILURE;
}

我看到你的代码有两个问题。首先,set_tty_options函数似乎没有完全初始化tty_options结构体。这可能解释了“如果我先运行X,我的程序就能工作,但是单独运行会挂起/失败”的问题。这是一个程序不正确或未完全初始化其环境的典型症状。其次,对于规范输入,set_blocking函数是错误的。c_cc [VMIN]c_cc [VTIME]只应用于非规范(也称为原始)输入。对于规范输入的非阻塞read(),请使用fcntl()进行设置。 - sawdust
2个回答

1
我认为您想在打开标志中添加| O_SYNC以坚持同步I/O。不过,我怀疑这不会导致问题。
但是,我认为您想忽略断开信号,这被报告为一个NUL字符,就像您所获得的一样:
tty_settings.c_iflag &= ~IGNBRK;         // ignore break signal

此外,您需要确保关闭输入处理程序,以便收到退格、^C、^ \等不会触发任何反应。
tty_settings.c_lflag = 0;                // no signaling chars, no echo,
                                         // no canonical processing

看起来你已经在使用我的set_blocking()函数,所以应该没问题。


0
这是我最终做的。我通过基本上从 cutecom的源代码中复制和粘贴部分来解决了这个问题。
  1. 打开时...

    int fd, n;
    fd = open (device_path, O_RDONLY | O_NOCTTY | O_NDELAY);
    
    ... 检查 fd 是否出错 ...
    
    n = fcntl(ail_info->ail_serial_fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, n & ~O_NDELAY);
    
  2. 你不能像我一样设置波特率。你必须使用定义好的 B38400

    baud = B38400;

  3. 然后,我添加了 wallyk 的答案。

    tty_settings.c_lflag = 0;

编辑:根据sawdust的评论,我找到了一种更好的将其设置为原始输入的方法。

tty_options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

它有效。


然后,我添加了wallyk的答案。tty_settings.c_lflag = 0; -- 你仍然没有正确配置串口。c_oflag设置为什么?请注意,根据POSIX,不建议对termios结构成员进行硬赋值。您应该调用tcgetattr(),然后启用或禁用每个属性字段(就像您对c_cflag所做的那样)。请参阅POSIX操作系统串行编程指南。您正在使用POSIX调用,因此请遵循它们的规则。 - sawdust

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