繁体   English   中英

如何在Linux中从串行端口接收完整数据

[英]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创作者中撰写。 我面临的问题是,无论何时我发送诸如AB或任何其他单个字符的字符。 它收到它。 但是,当我发送完整的字符串时,它会自动中断。 看下图:

在此处输入图片说明

如您在图像中看到的,它像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提供了一个更好的屏蔽信号的示例,而不是将其关闭(可能导致竞态)。 在调用sigactionMainWindow::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM