[英]How to receive complete data from serial port in linux
我正在尝试进行串行通信应用程序。 我有一台正在运行qq linux映像的设备。 我需要为该设备编写串行代码应用程序。 因为交叉编译器设置为QT4.8.7,所以它不包括QSerialPort
。 因此,我正在跟踪此链接进行串行通信,并且在该链接上也找到了很多很好的例子。
下面是代码:
void MainWindow::SerialOpen(QString PORT)
{
fd = open(PORT.toStdString().c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyLP0\n");
exit(1);
}
saio.sa_handler = signal_handler_IO;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
fcntl(fd, F_SETFL, FNDELAY);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, O_ASYNC );
tcgetattr(fd,&termAttr);
cfsetispeed(&termAttr,B9600);
cfsetospeed(&termAttr,B9600);
termAttr.c_cflag &= ~PARENB;
termAttr.c_cflag &= ~CSTOPB;
termAttr.c_cflag &= ~CSIZE;
termAttr.c_cflag |= CS8;
termAttr.c_cflag |= (CLOCAL | CREAD);
termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
termAttr.c_oflag &= ~OPOST;
tcsetattr(fd,TCSANOW,&termAttr);
qDebug("Serial Port configured....\n");
}
为了阅读,我使用:
void signal_handler_IO (int status)
{
char buf [100];
int n = read (fd, buf, sizeof buf);
if(n > 0)
{
buf[n] = '\0';
printf("Receive OK %s\n",buf);
}
}
我正在使用基于事件的串行读取。 我在QT创作者中撰写。 我面临的问题是,无论何时我发送诸如A
或B
或任何其他单个字符的字符。 它收到它。 但是,当我发送完整的字符串时,它会自动中断。 看下图:
如您在图像中看到的,它像p
l
h
一样接收char,但是随后我向hello world
发送了消息。 它打破了它,首先收到了hello
,然后是world
。 我再次向hello world
发送了消息,它收到了he
然后是llo
然后是worl
,然后是d
。 为什么显示这种行为。 请帮忙。 谢谢。
您正在小批量接收数据。 尝试在while循环中运行read
函数,以将所有块附加到一条消息中,如下所示:
#include <cstring> // needed for strcat.
#include <errno.h> // needed for strerror and errno
void signal_handler_IO (int status)
{
char buf [100];
char msg[1024];
int n;
int length = 0;
while((n = read (fd, buf, (sizeof buf)-1)) > 0)
{
buf[n] = '\0';
// you can add a check here to see if (length+n) < 1024
strcat(msg, buf);
length += n;
}
if(n<0)
{
//error handling
//EDIT: adding error handling
fprintf(stderr, "Error while receiving message: %s\n", strerror(errno));
return;
}
printf("Receive OK: '%s'\n", msg);
}
在读取数据时需要关闭信号处理,以免对每个新的数据块都调用信号处理程序。 阅读完之后,需要恢复处理程序。 编辑 :感谢@MarkPlotnick提供了一个更好的屏蔽信号的示例,而不是将其关闭(可能导致竞态)。 在调用sigaction
到MainWindow::SerialOpen
掩盖信号之前,添加以下两行,以便在处理信号时不会再次调用处理程序:
sigemptyset(&saio.sa_mask);
sigaddset(&saio.sa_mask, SIGIO);
msg
的大小仅是示例,您可以将其设置为适合该消息的任何值。 另外,如果您使用的是c ++,那么最好使用std::string
代替msg
的数组。
注意(sizeof buf)-1
,如果您读取了所有字符,则在数组末尾没有空格来容纳'\\0'
。
另一个编辑 :在我们的聊天对话之后,事实证明,当没有更多字符要读取时, read
正在阻塞(即使使用O_NDELAY
标志调用open
来进行非阻塞读取)。 要解决此问题,可以先检查有多少字节可读取:
while(true)
{
size_t bytes_avail;
ioctl(fd, FIONREAD, &bytes_avail);
if(bytes_avail == 0)
break;
int n = read (fd, buf, (sizeof buf)-1);
if(n<0)
{
//error handling
fprintf(stderr, "Error while receiving message: %s\n", strerror(errno));
return;
}
buf[n] = '\0';
// you can add a check here to see if (length+n) < 1024
strcat(msg, buf);
length += n;
}
QT4.8.7,因此它不包含QSerialPort
您可以从源代码构建QSerialPort并使用它。 请阅读Wiki: https : //wiki.qt.io/Qt_Serial_Port
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.