“cu”可以从串口读取,但我自己的C程序不能

问题描述 投票:0回答:1

回答,感谢评论者:

有些终端设置的默认值与原始的、未经过滤的串行传输不一致。添加下面的代码解决了问题。我确定我设置/清除的东西比我需要的多。

struct termios options;
tcgetattr(fd, &options);

cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);

options.c_iflag &= ~(IXOFF | IXANY | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON);
options.c_cflag &= ~(CRTSCTS | CLOCAL | CSIZE | PARENB | CSTOPB);
options.c_cflag |= CREAD | CS8;
options.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE | ECHONL | IEXTEN);
options.c_oflag &= ~(OPOST);
options.c_cc[VMIN]  = 1;
options.c_cc[VTIME] = 0;

tcsetattr(fd, TCSANOW, &options);

原问题:

我有一个设备想要连接到运行 Ubuntu 20.04 的 Nvidia Jetson Orin Nano。它需要 TTL 级串行通信,并且我使用合适的 USB 转串行电缆。我还将我的用户添加到适当的组中以访问串行设备。

首先,我可以使用 cu 成功访问串行设备。此命令有效:

cu -f -s 115200 -l /dev/ttyUSB0

接下来我要编写自己的 C 程序来访问同一设备。

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

int main() {
    int r;

    int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
    if (fd == -1) {
        perror("tty ");
        return 1;
    }

    // Get current serial port options
    struct termios options;
    r = tcgetattr(fd, &options);
    if (r < 0) {
        perror("tcgetattr ");
        return 1;
    }

    // Set baud rate to 115200
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);

    // Disable flow control (CTS and RTS)
    options.c_cflag &= ~CRTSCTS;

    // Set new serial port options
    r = tcsetattr(fd, TCSANOW, &options);
    if (r < 0) {
        perror("tcsetattr ");
        return 1;
    }

    char buf;
    while (1) {
        r = read(fd, &buf, 1);
        if (r < 0) {
            perror("read ");
            return 1;
        }
        printf("%02x\n", 255 & buf);
    }

    close(fd);
    return 0;
}

不幸的是,这个程序不起作用。打开成功。 tcgetattr 和 tcsetattr 成功。但阅读只是坐在那里,什么也没做。

我在 cu 上运行了 strace,看看有什么不同(请参阅下面的部分跟踪粘贴),但除了检查锁定文件(不存在)之外,我无法判断这里可能相关的内容.

有人对我做错了什么有任何想法吗?

谢谢!

[Mostly what precedes this is things like dynamically linking shared object libraries, setting signal handlers, closing already-closed fd's, and trying to access various files that don't exist.]
getpid()                                = 17612
openat(AT_FDCWD, "/var/lock/TMP00000044cc", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
write(3, "     17612\n", 11)            = 11
close(3)                                = 0
linkat(AT_FDCWD, "/var/lock/TMP00000044cc", AT_FDCWD, "/var/lock/LCK..ttyUSB0", 0) = 0
unlinkat(AT_FDCWD, "/var/lock/TMP00000044cc", 0) = 0
geteuid()                               = 1000
getuid()                                = 1000
getegid()                               = 1000
getgid()                                = 1000
setregid(1000, 1000)                    = 0
setreuid(1000, 1000)                    = 0
openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NONBLOCK) = 3
geteuid()                               = 1000
getuid()                                = 1000
getegid()                               = 1000
getgid()                                = 1000
setregid(1000, 1000)                    = 0
setreuid(1000, 1000)                    = 0
fcntl(3, F_GETFD)                       = 0
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
faccessat(AT_FDCWD, "/dev/ttyUSB0", R_OK|W_OK) = 0
fcntl(3, F_GETFL)                       = 0x20802 (flags O_RDWR|O_NONBLOCK|O_LARGEFILE)
fcntl(3, F_SETFL, O_RDWR|O_LARGEFILE)   = 0
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCFLSH, TCIFLUSH)              = 0
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TIOCSCTTY, 0)                  = -1 EPERM (Operation not permitted)
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_STOP or TCSETSW, {B115200 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B115200 -opost -isig -icanon -echo ...}) = 0
faccessat(AT_FDCWD, "/dev/ttyUSB0", R_OK|W_OK) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x2), ...}) = 0
write(1, "\7Connected.\n", 12)          = 12
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
pipe2([4, 5], 0)                        = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xffffa25c8d00) = 17613
close(5)                                = 0
read(0, 0xffffe67adad6, 1)              = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=17614, si_uid=1000} ---
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=17613, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
ioctl(0, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(2, "cu: Got termination signal\n", 27) = 27
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
close(4)                                = 0
linux serial-port
1个回答
0
投票

有人对我做错了什么有任何想法吗?

您的 termios 配置不完整。您只需配置波特率和硬件流量控制,甚至不需要设置成帧。因此,您可以重复使用现有的线路和 termios 设置。
所以你甚至不知道串行终端是处于规范模式还是原始模式!
您所知道的是,串行终端被阻塞,等待满足某些未知条件。请参阅 Linux 阻塞与非阻塞串行读取


有一些终端设置的默认值与...不一致

您根本不能依赖任何“default”termios设置,因为(a)不存在“default配置”之类的东西,并且(b)您不知道先前的程序留下该串行终端的配置在.
如果您希望您的程序可靠且健壮,您的程序必须执行完整的 termios 配置,并设置或清除它所需的每个属性。


您的“答案”在声明中存在错误:

options.c_cflag &= ~(CRTSCTS | CLOCAL | CSIZE | PARENB | CSTOPB);

CLOCAL 属性应始终启用,因为它应该启用接收器。有趣的是,您声称此有缺陷的代码可以从串行终端读取数据。

我确定我设置/清除的内容比我需要的多。

有关noncanonical模式的最小termios配置,请参阅此答案

© www.soinside.com 2019 - 2024. All rights reserved.