UART 回复包括之前的命令?

UART reply includes previous command?

我正在尝试使用 C 程序在 Linux 环境中读取 UART 设备,但在使用屏幕与 UART 通信时我遇到了不同的结果。

我用来测试UART通信的C代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <getopt.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <signal.h>
#include <ctype.h>

bool loop;

void sigHandler(int32_t sig)
{   
    if(sig == SIGINT)
    {
        printf("Catched SIGINT");
        loop = false;
    }
}

int main(int argc, char *argv[])
{
    char *devname = argv[1];
    int fd = -1;

    int nread = -1;
    int nwrite = -1;

    int ret;

    struct termios t_new = {0};
    struct termios t_old = {0};


    signal(SIGINT, sigHandler);


    fd = open(devname, O_RDWR | O_NOCTTY |O_NONBLOCK);
    if(fd > 0)
    {   
        printf("TTY open ! Configuring TTY"); 
    }
    else
    {
        fd = -1;
        return 1;
    }

    ret = tcgetattr(fd, &t_old);
    if(ret < 0)
    {
        perror("tcgetattr ");
        close(fd);
        fd = -1;
        return 1;
    }

    t_new = t_old;
    t_new.c_cflag = (B9600 | CS8 | CREAD );
    t_new.c_oflag = 0;
    t_new.c_iflag = 0;
    t_new.c_lflag = 0;

    ret = tcsetattr(fd, TCSANOW, &t_new);

    loop = true;
    while(loop)
    {
        char s[] = "at+gmi=?\r\n";
        nwrite = write(fd, s, strlen(s));
        if(nwrite == strlen(s))
        {
            fd_set rfd;
            struct timeval tm = {.tv_sec = 0, .tv_usec = 500000};
            FD_ZERO(&rfd);
            FD_SET(fd, &rfd);

            char buffer[64] = {0};

            if(select(fd + 1, &rfd, NULL, NULL, &tm) > 0)
                nread = read(fd, buffer, sizeof(buffer));

            if(nread > 0)
                printf("Reply is: %s\n", buffer);
        }

        usleep(500000);
    }
}

但是当我阅读回复时,它总是包含我发送的字符串。 我在使用 screen.

时没有遇到这个问题

使用 Linux 在 C 中读取 UART 的最佳方法是什么? 多路复用方式(使用select)会导致问题吗?

编辑 为了完整起见,输出为:

Reply is: at+gmi=?

OK

还有,有时候什么都不看。

But when I read the reply, it always includes the string I have sent.

由于您的 termios 配置消除了本地回显属性并且您正在发送 AT 调制解调器命令,您应该尝试发送 ATE0 命令以禁用调制解调器的回显。

I don't experience this problem using screen.

此观察确认连接的调制解调器已启用回显。

当您键入时,AT 命令会(由调制解调器)回显,但在这种情况下您不反对接收到的数据(因为您想查看您键入的内容)。
如果调制解调器没有启用回显,那么您会抱怨您在 screen 中键入的内容不可见。

使用终端仿真程序(如screen)时需要IOW回显,但通过程序发送数据时需要禁用回显。

What is the best way to read from an UART in C using Linux ?

(从技术上讲,您不是从 "UART" 读取数据,而是从完全缓冲所有输入和输出的串行终端读取数据。)
符合 POSIX 标准的代码,如 Setting Terminal Modes Properly 中所述 Serial Programming Guide for POSIX Operating Systems 会比你现在拥有的要好得多。
我很惊讶它能正常工作(例如 CREAD 未启用)。

Could the multiplexed way (using select) causing the problems ?

不是回显 "problem"。
您的程序不会做任何需要使用 select() 和非阻塞模式的事情。

Also, sometimes I don't read anything.

当您编写不 POSIX 兼容的代码时,您不应期望可靠的程序行为。