gpt4 book ai didi

c++ - linux如何从串口接收完整的数据

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:05:12 27 4
gpt4 key购买 nike

我正在尝试做一个串行通信应用程序。我有一台运行 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 Creator 中编写它。我面临的问题是,每当我发送 AB 或任何其他单个字符时。它接收它。但是当我发送完整的字符串时,它会自动中断。看看下面的图片:

enter image description here

正如你在图片中看到的那样,它接收到类似 p l h 的字符,但随后我发送了 hello world。它打破它并首先接收到 hello 然后是 world。我再次发送了 hello world 它收到了 he 然后 llo 然后 worl 然后 d。为什么这会显示出这种行为。请帮忙。谢谢。

最佳答案

您正在接收小块数据。尝试在 while 循环中运行 read 函数,将所有 block 附加到一条消息中,如下所示:

#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);
}

读取数据时需要关闭信号处理,这样信号处理程序就不会为每个新数据 block 调用。完成读取后,需要恢复处理程序。编辑:感谢@MarkPlotnick 提供了一个更好的示例来屏蔽信号而不是将其关闭(可能导致竞争条件)。在将 sigaction 调用到 MainWindow::SerialOpen 之前添加这两行以屏蔽信号,以便在处理信号时不会再次调用处理程序:

sigemptyset(&saio.sa_mask);
sigaddset(&saio.sa_mask, SIGIO);

msg 的大小只是一个示例,您可以将其设置为适合消息的任何值。此外,如果您使用的是 C++,那么最好使用 std::string 而不是 msg 的数组。

请注意 (sizeof buf)-1,如果您读取所有字符,则数组末尾的 '\0' 将没有空间。

另一个编辑:在我们的聊天对话之后发现当没有更多字符可读时 read 被阻塞(即使 open使用 O_NDELAY 标志调用以进行非阻塞读取)。要解决这个问题,可以先检查有多少字节可供读取:

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;
}

关于c++ - linux如何从串口接收完整的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43448212/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com