读取串口这样的工作当然不应该放在主线程中去做,开一个后台线程监控串口,有数据输入时接收完整的一帧,提取数据,然后传给主线程处理是比较合理的做法。Qt中提供了与平台无关的线程类QThread,线程间的通讯可以使用QEvent来进行。网上常见的读取串口数据的方式是在一个死循环中不断的查询(读取串口数据),这样显然是对cpu资源的浪费。使用中断方式是一个理智的选择。现在的问题就归结为如何在线程中使用中断方式来读取数据,然后用QEvent(其实是其子类)传回主线程。用QEvent传送数据比较简单,可以参见这里。用中断方式读取串口数据本是件再普通不过的事情了,但由于鄙人对linux下的串口编程不熟悉,颇是费了一番周折,最后终于在网上找到了解决方法,记录下来备忘~
实际上采用了linux串口的非同步式输入方式。具体说来,就是调用read操作后,立即返回,待完成后会发出讯号给设置好的回调处理函数,在回调函数里可以完成QEvent的发送。
给出一个例子代码:
#include
#include
#include
#include
#include
#include
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX 系统相容 */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status); /* 定义讯号处理程序 */
int wait_flag=TRUE; /* 没收到讯号的话就会是 TRUE */
main()
{
int fd,c, res;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
/* 开启装置为 non-blocking (读取功能会马上结束返回) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd <0)>
/* 在使装置非同步化前, 安装讯号处理程序 */
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* 允许行程去接收 SIGIO 讯号*/
fcntl(fd, F_SETOWN, getpid());
/* 使档案ake the file descriptor 非同步 (使用手册上说只有 O_APPEND 及
O_NONBLOCK, 而 F_SETFL 也可以用...) */
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* 储存目前的序列埠设定值 */
/* 设定新的序列埠为标准输入程序 */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* 等待输入讯号的回圈. 很多有用的事我们将在这做 */
while (STOP==FALSE) {
printf("./n");usleep(100000);
/* 在收到 SIGIO 後, wait_flag = FALSE, 输入讯号存在则可以被读取 */
if (wait_flag==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%s:%d/n", buf, res);
if (res==1) STOP=TRUE; /* 如果只输入 CR 则停止回圈 */
wait_flag = TRUE; /* 等待新的输入讯号 */
}
}
/* 回存旧的序列埠设定值 */
tcsetattr(fd,TCSANOW,&oldtio);
}
/*********************************************
* 讯号处理程序. 设定 wait_flag 为 FALSE, 以使上述的回圈能接收字元
**********************************************
void signal_handler_IO (int status)
{
printf("received SIGIO signal./n");
wait_flag = FALSE;
}
没有评论:
发表评论