[英]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創作者中撰寫。 我面臨的問題是,無論何時我發送諸如A
或B
或任何其他單個字符的字符。 它收到它。 但是,當我發送完整的字符串時,它會自動中斷。 看下圖:
如您在圖像中看到的,它像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提供了一個更好的屏蔽信號的示例,而不是將其關閉(可能導致競態)。 在調用sigaction
到MainWindow::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.