【问题标题】:How to read character using serial port in Linux如何在 Linux 中使用串口读取字符
【发布时间】:2016-02-04 06:02:37
【问题描述】:

我尝试使用串口“/dev/ttyS0”读取串行原始字节。在我的程序中,我想做的是按下字母并立即看到我介绍的字母重复而不按 ENTER。例如,如果我按字母“a”,我想在它旁边看到另一个“a”。

我的代码在这里:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

int main()
{
        int n = 0, fd = 0;

        struct termios term,trm;

        printf("%d\n",getpid());

        fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

        if (fd == -1)
        {
                perror("open");
                return 1;
        }
        else
        {
                fcntl(fd, F_SETFL, 0);
                perror("Port");
        }

        if (n = tcgetattr(fd, &term) == -1)
        {
                perror("tcgetattr");
                return 1;
        }

        if (n = cfsetispeed(&term, B115200) == -1)
        {
                perror("cfsetispeed");
                return 1;
        }

        if (n = cfsetospeed(&term, B115200) == -1)
        {
                perror("cfsetospeed");
                return 1;
        }

        term.c_cflag |= (CLOCAL | CREAD);
        term.c_cflag &= ~PARENB;
        term.c_cflag &= ~CSTOPB;
        term.c_cflag &= ~CSIZE;
        term.c_cflag |= CS8;
        term.c_cflag &= ~CRTSCTS;
        term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        term.c_iflag &= ~(IXON | IXOFF | IXANY);
        term.c_iflag |= (INPCK | ISTRIP);
        term.c_oflag &= ~OPOST;

        unsigned char c,d;
        ssize_t s=0;

        tcflush(fd, TCIOFLUSH);

        system("/bin/stty raw");
        while((c=getchar()) != 'q')
        {
                write(fd, &c,1);

                term.c_cc[VMIN] = 1;
                term.c_cc[VTIME] = 0;

                tcsetattr(fd, TCSANOW, &term);

                if((s=read(fd, &d,1)) != -1)
                {
                        perror("read");
                        printf("%c",d);
                }
        }
        system("/bin/stty cooked");
        close(fd);
        return 0;
}

【问题讨论】:

  • 不需要将您的端口配置集成到while循环中。最好将它们放在 tcflush 调用之前。另外,使用 system() 通过 stty 配置端口也不是必须的,您已经使用 termios struct 进行配置。
  • 包括 fntl、stlib、stdio。 termios 并添加返回值。请先编译您的代码,然后再将其发布到此处
  • " 我想要做的是按下字母并立即看到我介绍的字母重复而不按 ENTER" -- 这似乎只是一个关于 stdinstdout,与串口无关。
  • 假设您已经使用termios正确配置了串口,那么发送到串口的字符可以回显 (a) 本地 i> 通过在 c_lflag 中启用 ECHO,和/或 (b) 远程 由串行另一端的设备关联。请注意,这意味着您可以获得单回声或双回声(或根本没有回声),具体取决于 everything 的设置方式。

标签: c linux serial-port tty


【解决方案1】:

我不知道这是否是您正在寻找的解决方案,但您必须禁用标准输入缓冲以使 getchar 退出每个用户输入的字符。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

int main()
{
        int n = 0, fd = 0;

        struct termios term, old_stdin, new_stdin;

        printf("%d\n",getpid());

        fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);

        if (fd == -1)
        {
                perror("open");
                return 1;
        }
        else
        {
                fcntl(fd, F_SETFL, 0);
                perror("Port");
        }

        if (n = tcgetattr(fd, &term) == -1)
        {
                perror("tcgetattr");
                return 1;
        }

        if (n = cfsetispeed(&term, B115200) == -1)
        {
                perror("cfsetispeed");
                return 1;
        }

        if (n = cfsetospeed(&term, B115200) == -1)
        {
                perror("cfsetospeed");
                return 1;
        }

        term.c_cflag |= (CLOCAL | CREAD);
        term.c_cflag &= ~PARENB;
        term.c_cflag &= ~CSTOPB;
        term.c_cflag &= ~CSIZE;
        term.c_cflag |= CS8;
        term.c_cflag &= ~CRTSCTS;
        term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
        term.c_iflag &= ~(IXON | IXOFF | IXANY);
        term.c_iflag |= (INPCK | ISTRIP);
        term.c_oflag &= ~OPOST;

        unsigned char c,d;
        ssize_t s=0;

        tcflush(fd, TCIOFLUSH);
        term.c_cc[VMIN] = 1;
        term.c_cc[VTIME] = 0;

        tcsetattr(fd, TCSADRAIN, &term);

        // get the terminal settings for stdin 
        tcgetattr(STDIN_FILENO,&old_stdin);

        new_stdin = old_stdin;

        // disable canonical mode (buffered i/o) and local echo 
        new_stdin.c_lflag &=(~ICANON & ~ECHO);

        // set the new settings
        tcsetattr(STDIN_FILENO,TCSANOW,&new_stdin);

        while((c=getchar()) != 'q')
        {
            write(fd, &c,1);

            if((s=read(fd, &d,1)) != -1)
            {
                perror("read");
                printf("%c",d);
            }
        }
        close(fd);

        // Restore the old stdin setup
        tcsetattr(STDIN_FILENO,TCSANOW,&old_stdin);

        return 0;
}

【讨论】:

    【解决方案2】:

    您应该将终端设备的模式更改为“原始”,通过使用

    tty.setraw(file_descriptor)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多