簡體   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