我正在尝试读取从 tty/USB0 发送的数据并以字节格式打印出来。
问题:
- 我希望在读取字节达到 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 个问题:
当我修改 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.
参见例如this或this如何以编程方式实现这一点(没有检查代码,但应该很容易找到它)。
或者您可以使用例如strace
或 ltrace
来检查 stty -F/dev/ttyUSB0 raw
的作用(或阅读描述它的手册页)。
编辑>
关于不带换行符的 printf
-- fflush(stdout);
应该会有所帮助(另一个行缓冲正在发生)。
关于Linux read() 系统调用花费的时间比我预期的要长(串口编程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32883248/