2017-04-17 66 views
0

我正試圖做一個串行通信應用程序。我有一個運行angstrom qt linux映像的設備。我需要爲該設備編寫串行代碼應用程序。由於交叉編譯器是爲QT4.8.7設置的,所以它不包含QSerialPort。所以我正在關注這個串行通信的link,我也發現了很多很好的例子。如何在Linux中從串口接收完整數據

下面是代碼:

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或任何其他單個字符的字符。它收到它。但是當我發送完整的字符串時,它會自動中斷。看看下面的圖片:

enter image description here

正如你可以在圖片中看到,它接收燒焦像plh但後來我送hello world。它打破它,首先收到hello,然後world。我再次發送hello world它收到he然後​​然後worl然後d。爲什麼會顯示這種行爲。請幫忙。謝謝。

回答

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提供了一個掩蔽信號而不是關閉信號(可能會導致競爭狀態)的更好示例。

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

msg的大小僅僅是一個例子,你可以將它設置:調用sigactionMainWindow::SerialOpen來屏蔽信號,以使處理器不會再次當信號被處理調用之前添加這兩條線以適合消息的任何值。另外,如果您使用的是C++,那麼最好使用std::string而不是msg的數組。

請注意(sizeof buf)-1,如果您閱讀所有字符,則在陣列末尾將沒有空間存放。

ANOTHER編輯:我們的聊天談話之後,它原來,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; 
} 
+1

'error:expected;之前長度:) :) – CZAbhinav

+0

@CZAbhinav感謝您的快速擡頭:) – Rogus

+0

@羅格斯它沒有打印任何東西在終端上。即使是recive ok –

0

QT4.8.7, so it do not include the QSerialPort

您可以從源建立QSerialPort並使用它。請閱讀Wiki:https://wiki.qt.io/Qt_Serial_Port

+0

從哪裏可以獲得QSerialPort源。在這一步「從QtCreator構建和安裝」中提到的第一點是下載QSerialPort源,但是它們提供的鏈接上沒有提供可下載的文件。我從哪裏可以獲得QSerialPort源 –