Linux read() 系统调用花费的时间比我预期的要长(串口编程)

标签 linux serial-port system-calls

我正在尝试读取从 tty/USB0 发送的数据并以字节格式打印出来。

问题:

  1. 我希望在读取字节达到 40 时打印出数据,但是,时间比我预期的要长得多。 read() 系统调用挂起,我相信数据应该已经大于 40。数据最终会被打印出来,但应该不会花这么长时间。我在这个编程中犯了什么错误吗?

谢谢

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define BAUDRATE B9600            
#define MODEMDEVICE "/dev/ttyUSB0"

#define FALSE 0
#define TRUE 1

main()
{
int fd,c, res;
struct termios oldtio,newtio;
unsigned char buf[40];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }

tcgetattr(fd,&oldtio);
bzero(&newtio, sizeof(newtio));

newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;

newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 1;
newtio.c_lflag = ICANON;

tcflush(fd, TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

int i;
while (1) {
    res = read(fd,buf,40);
    if(res==40){
        printf("res reaches 40 \n");
    }
    printf("res: %d\n",res);
    for(i=0;i<res;++i){
    printf("%02x ", buf[i]);
    }
    return;
    }
}

--------------------原始模式代码------------------------

  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <termios.h>
  #include <stdio.h>

  #define BAUDRATE B9600
  #define MODEMDEVICE "/dev/ttyUSB0"
  #define _POSIX_SOURCE 1 /* POSIX compliant source */
  #define FALSE 0
  #define TRUE 1

  volatile int STOP=FALSE;

  main()
  {
    int fd,c, res;
    struct termios oldtio,newtio;
    unsigned char buf[255];

    fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
    if (fd <0) {perror(MODEMDEVICE); exit(-1); }

    tcgetattr(fd,&oldtio); /* save current port settings */

    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;

    /* set input mode (non-canonical, no echo,...) */
    newtio.c_lflag = 0;

    newtio.c_cc[VTIME]    = 0;   
    newtio.c_cc[VMIN]     = 40;   

    tcflush(fd, TCIFLUSH);
    tcsetattr(fd,TCSANOW,&newtio);

    int i;
    while (STOP==FALSE) {       
      res = read(fd,buf,255);   
      for( i=0;i<res;++i){
        printf("%02x \n", buf[i]);
      }
    }
    tcsetattr(fd,TCSANOW,&oldtio);
  }

一旦缓冲区容量已满(即 40 ),它现在可以打印出数据。 1 个问题:

  1. 当我修改 printf 时

    printf("%02x", buf[i]); (删除“\n”) 当缓冲区已满时,它不会打印出来,直到接收到更多字节。为什么会出现这种情况?

谢谢

最佳答案

您需要将终端切换到原始模式以禁用行缓冲。

引用this answer :

The terms raw and cooked only apply to terminal drivers. "Cooked" is called canonical and "raw" is called non-canonical mode.

The terminal driver is, by default a line-based system: characters are buffered internally until a carriage return (Enter or Return) before it is passed to the program - this is called "cooked". This allows certain characters to be processed (see stty(1)), such as Cntl-D, Cntl-S, Ctrl-U Backspace); essentially rudimentary line-editing. The terminal driver "cooks" the characters before serving them up.

The terminal can be placed into "raw" mode where the characters are not processed by the terminal driver, but are sent straight through (it can be set that INTR and QUIT characters are still processed). This allows programs like emacs and vi to use the entire screen more easily.

You can read more about this in the "Canonical mode" section of the termios(3) manpage.

参见例如thisthis如何以编程方式实现这一点(没有检查代码,但应该很容易找到它)。

或者您可以使用例如straceltrace 来检查 stty -F/dev/ttyUSB0 raw 的作用(或阅读描述它的手册页)。

编辑>

关于不带换行符的 printf -- fflush(stdout); 应该会有所帮助(另一个行缓冲正在发生)。

您可以考虑阅读 this也许this .

关于Linux read() 系统调用花费的时间比我预期的要长(串口编程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32883248/

相关文章:

c - 多次读取被警报中断

api - 可以通过程序访问传感器读数的家庭气象站?

c - "creat"Unix系统调用

Linux,系统调用表,32 和 x64

linux - 我无法重新启动 apache 网络服务器

php - 很简单的mod_rewrite问题

c# - Unity无法打开COM口

linux - 拦截系统调用(参数传递到哪里)

无法使用 libpcap 捕获数据包

php - 了解 ssh2_exec() 中的 PTY 参数