我正在尝试进行串行通信应用程序。我有一个运行angstrom qt linux映像的设备。我需要为该设备编写串行代码应用程序。因为交叉编译器是为QT4.8.7设置的,所以它不包括QSerialPort
。所以我跟着这个link进行串行通信,我也发现了许多很好的例子。
以下是代码:
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
之类的字符,但之后我发送了hello world
。它打破了它并首先收到hello
然后world
。我再次发送hello world
,然后收到he
,然后llo
,然后worl
,然后d
。为什么会出现这种行为。请帮忙。感谢。
答案 0 :(得分:3)
您正在以小块的形式接收数据。尝试在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
正在阻止(即使open
被{{1}调用标志为非阻塞读取)。要解决此问题,可以先检查可读取的字节数:
O_NDELAY
答案 1 :(得分:0)
QT4.8.7,因此它不包括QSerialPort
您可以从源构建QSerialPort并使用它。请阅读Wiki:https://wiki.qt.io/Qt_Serial_Port