【问题标题】:How to receive complete data from serial port in linux如何在linux中从串口接收完整的数据
【发布时间】:2017-09-12 21:04:49
【问题描述】:

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

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

【问题讨论】:

    标签: c++ linux serialization


    【解决方案1】:

    您正在以小块的形式接收数据。尝试在 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 被阻塞(即使 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; 
    } 
    

    【讨论】:

    • @CZAbhinav 感谢您的快速提醒 :)
    • @Rogus 它没有在终端上打印任何东西。连receive都不行
    • 这意味着 read 返回 -1。稍等,让我添加错误处理@SAndrew 立即尝试
    • 还是不行。我也在编辑它。如果它有效,将更新它
    • 要在信号处理程序中阻止 SIGIO,在调用MainWindow::SerialOpen 中的 sigaction 之前执行sigemptyset(&amp;saio.sa_mask); sigaddset(&amp;saio.sa_mask, SIGIO); 可能更安全。这样一来,您就不会在信号可能再次出现之前尝试忽略信号处理程序中的信号的竞争条件。
    【解决方案2】:

    QT4.8.7,所以不包含QSerialPort

    您可以从源代码构建 QSerialPort 并使用它。请阅读维基:https://wiki.qt.io/Qt_Serial_Port

    【讨论】:

    • 从哪里可以获得 QSerialPort 源。在这一步Build and Install from QtCreator 提到的第一点是下载 QSerialPort 源,但在他们提供的链接上没有提供可下载的文件。?从哪里可以得到 QSerialPort 源
    猜你喜欢
    • 2015-08-04
    • 2022-01-22
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多