Terminal 终端提示失真且无法读取

Terminal 终端提示失真且无法读取,terminal,uart,termios,Terminal,Uart,Termios,我是linux编程新手。我按照web上的示例对控制台进行读/写操作,例如“/dev/ttyS0”。每次运行代码时,它都会退出,而不会提示用户编写输入。它还扭曲了终端提示(换行符),我无法看到我正在键入的内容。。。以下是我正在使用的代码: int main(int argc, char** argv) { struct termios tio; struct termios stdio; int tty_fd; /* fd_set rdset; */ printf("Plea

我是linux编程新手。我按照web上的示例对控制台进行读/写操作,例如“/dev/ttyS0”。每次运行代码时,它都会退出,而不会提示用户编写输入。它还扭曲了终端提示(换行符),我无法看到我正在键入的内容。。。以下是我正在使用的代码:

int main(int argc, char** argv)
{
  struct termios tio;
  struct termios stdio;
  int tty_fd;
  /* fd_set rdset; */

  printf("Please start with %s /dev/ttyS0 (for example)\n",argv[0]);
  unsigned char mesg='D';

  memset(&stdio,0,sizeof(stdio));
  stdio.c_iflag=0;
  stdio.c_oflag=0;
  stdio.c_cflag=0;
  stdio.c_lflag=0;
  stdio.c_cc[VMIN]=1;
  stdio.c_cc[VTIME]=0;
  tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
  tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
  fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);       // make the reads non-blocking

  memset(&tio,0,sizeof(tio));
  tio.c_iflag=0;
  tio.c_oflag=0;
  tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
  tio.c_lflag=0;
  tio.c_cc[VMIN]=1;
  tio.c_cc[VTIME]=5;

  tty_fd=open(argv[1], O_RDWR | O_NONBLOCK | O_NOCTTY);
  cfsetospeed(&tio,B115200);            // 115200 baud
  cfsetispeed(&tio,B115200);            // 115200 baud

  tcsetattr(tty_fd,TCSANOW,&tio);
  while (mesg != 'q') {
    if (read(tty_fd,&mesg,1)>0)        write(STDOUT_FILENO,&mesg,1);              // if new data is available on the serial port, print it out
    if (read(STDIN_FILENO,&mesg,1)>0)  write(tty_fd,&mesg,1);                     // if new data is available on the console, send it to the serial port
  }

  close(tty_fd);

  return(0);
}

当您在试验更改tty参数的代码时,您应该使用保存和恢复参数的脚本来包装对测试程序的调用,以防您的程序忽略了这一点

可以这样做:

 $ SAVED_TTY=$(stty -g)          # save the good settings once
 $ ./a.out ; stty $SAVED_TTY     # restore than after each run of the program
unsigned int modem_control_bits;

result = ioctl(tty_descriptor, TIOCMGET, &modem_control_bits);
/* check result for error, of course */

modem_control_bits |= TIOCM_LOOP; /* request loopback from serial port */

result = ioctl(tty_descriptor, TIOCMSET, &modem_control_bits);
/* check result for error */
stty
-g
选项使其将所有tty设置“pickle”输出到字符串中,该字符串可作为以后调用
stty
以恢复相同设置的参数

(正确编写的tty操作程序在退出时会小心地恢复终端设置,即使它们通过接收任何可以处理的致命信号而突然退出。)

至于如何循环回写入tty设备的内容的问题,tty子系统本身没有通用的功能。标准的tty行规程模块可以将输入的字符回显到输出中,这样当用户使用面向行的程序时,他们可以看到自己的输入,但是没有软件环回,tty设备可以借此假装接收它刚刚发送的一些字符

然而,一些串行硬件能够实现硬件环回:基本上,为了测试的目的,将UART TX线路与RX线路连接起来

Linux tty支持调制解调器控制ioctl,如果硬件支持,可以使用它来打开和关闭此功能。其形式为
TIOCMGET
TIOCMSET
ioctls。这些IOCTL使用的值是各种掩码的逻辑OR,其中一个是
TIOCM\u LOOP

因此,我相信建立硬件环回是这样的:

 $ SAVED_TTY=$(stty -g)          # save the good settings once
 $ ./a.out ; stty $SAVED_TTY     # restore than after each run of the program
unsigned int modem_control_bits;

result = ioctl(tty_descriptor, TIOCMGET, &modem_control_bits);
/* check result for error, of course */

modem_control_bits |= TIOCM_LOOP; /* request loopback from serial port */

result = ioctl(tty_descriptor, TIOCMSET, &modem_control_bits);
/* check result for error */
如果要求每个串行驱动程序设置
TIOCM_LOOP
,是否每个串行驱动程序都会报告错误尚不清楚,但硬件不支持。(我不认为仅仅因为结果为零,它就一定有效)


还有其他的
TIOCM.*
位,所以你可以做一些标准的事情,比如打开和关闭DTR,或者检测响铃指示灯是否打开等等。

你应该在循环中加入一些小的亚秒睡眠,否则它会通过非阻塞读取在100%的CPU上旋转。你是在代码中谈论
循环吗?顺便说一句,如何读回我刚才在终端“/dev/ttyS0”上写的字符。是的,代码中唯一的循环。你说的“读回角色”是什么意思<代码>/dev/ttyS0
将字符发送到串行端口。它们不会返回,除非您将串行端口置于环回模式,或者您有一些外部硬件将字符环回同一端口或另一端口。我的意思是回显我写的内容。你能建议一些语法来做到这一点吗?我会把它添加到答案中。“我在网络上遵循了这个例子……”——那么你可能使用了一个不好的例子。调用
memset(,0,)
然后将0分配给结构元素是多余的,可能会导致问题。按照POSIX的正确做法是调用
tcgetattr()
,然后修改各个属性。看见将
stdout
的属性归零肯定是错误的,并且会导致问题