線程+定時實現linux下的Qt串口編程php
做者:lizzy115 時間:2010,5,14linux
說明:本設計採用的是線程+定時實現linux下的Qt串口編程,而非網上資料很是多的Qt編寫串口通訊程序全程圖文講解系列,由於Qt編寫串口通訊程序全程圖文講解系列是很好實現,那只是在windows下面的,但是在linux下面實現串口的通訊並不是如此,緣由在於QextSerialBase::EventDriven跟QextSerialBase::Polling這兩個事件的區別,EventDriven屬於異步,Polling屬於同步,在windows下面使用的是EventDriven很容易實現,只要有數據就會觸發一個串口事件,網上說linux下面須要的是Polling,但是仍是不行的,只要串口有數據的時候他會在QByteArray temp = myCom->readAll(); 這句一直讀取數據,沒能退出,直到斷掉串口的時候才能把接受到的串口數據經過ui->textBrowser->insertPlainText(temp);打印在界面上,一直沒能解決這個問題,因此只好採用線程+定時實現linux下的Qt串口編程進行設計。ios
1、安裝環境:編程
系統平臺:Ubuntu-8.04,內核2.6.24-27-generic,圖形界面小程序
2、軟件需求及下地地址:windows
Qt版本 qt-linux-SDK-4.6.2多線程
注意:此處使用的是qt-linux-SDK-4.6.2版本,編譯經過了,以後須要把他移植到qt-embedded-linux-opensource-src-4.5.3.tar.gz,經過qte編譯後移植到開發板中,採用的測試開發板爲Micro2440,app
下載地址:略異步
3、程序編寫過程ide
程序編程流程:
先新建一個工程空白工程,再創建Ui文件,經過designer進行Ui界面設計,設計完保存,編譯生成ui_mainwindow.h頭文件,編寫線程頭文件及線程處理.cpp文件,創建串口處理頭文件及 .cpp文件,最後完成main.cpp文件。
一、 Ui文件的設計:
創建Ui_MainWindow主窗口,在窗口上添加三個QPushButton,分別命名爲closeButton、writeButton、readButton,再添加一個QTextBrowser顯示串口接收數據,保存退出,編譯一下就能夠生成ui_mainwindow.h文件。
二、線程程序設計:
編寫一個線程程序,其不須要進行界面設計,直接實現線程的管理,實現串口的收發工做,其主要程序及說明以下:
1) 新建一個thread.h頭文件,內容以下:
#ifndef THREAD_H
#define THREAD_H
#include
class Thread:public QThread
{
Q_OBJECT
public:
Thread();
char buf[128];
volatile bool stopped;
volatile bool write_rs;
volatile bool read_rs;
protected:
virtual void run();
};
#endif
程序定義一個Thread類,它繼承於QThread,設有一些變量和一個run函數,virtual表示爲虛函數,你也能夠去掉,加上去會增長一些內存開銷,但提升了效率,對於這個小程序是看不出什麼效果的,volatile爲一函數數據類型,是一個類型修飾符(type specifier)。它是被設計用來修飾被不一樣線程訪問和修改的變量,其能夠在不一樣數據類型間進行轉化,保證對此變量的讀寫操做都不會被優化。若是沒有volatile,基本上會致使這樣的結果:要麼沒法編寫多線程程序,要麼編譯器失去大量優化的機會。
2)新建一個thread.cpp文件,內容以下:
#include"thread.h"
#include
#include
#include
#include
#include
#include
#include
#include
#define BAUDRATE B9600
#define RS_DEVICE "/dev/ttyS0" //串口1
//#define RS_DEVICE "/dev/ttySAC1" //串口1
Thread::Thread()
{} //析構
void Thread::run() //這就是線程的具體工做了
{
int fd,c=0,res;
struct termios oldtio,newtio; //termios結構是用來保存波特率、字符大小等
printf("start... ");
fd=open(RS_DEVICE,O_RDWR|O_NOCTTY); //以讀寫方式打開串口。不控制TTY
if(fd<0)
{
perror("error");
exit(1); //失敗退出
}
printf("Open... ");
tcgetattr(fd,&oldtio); //保存當前設置到oldtio
bzero(&newtio,sizeof(newtio)); //清除newtio結構,並從新對它的成員設置以下
newtio.c_cflag=BAUDRATE|CS8|CLOCAL|CREAD; //9600、8位、忽略DCD信號、啓用接收裝置
newtio.c_iflag|=IGNPAR; //忽略奇偶
newtio.c_oflag=0;
newtio.c_lflag=0;
newtio.c_cc[VMIN]=0;
newtio.c_cc[VTIME]=100; //在規定時間(VTIME)內讀取(VMIN)個字符;
tcflush(fd,TCIFLUSH); //清除全部隊列在串口的輸入與輸出;
tcsetattr(fd,TCSANOW,&newtio); //把咱們的設置寫入termios
while(stopped) //stopped爲0時將退出線程
{
if(write_rs) //write_rs爲1時把字符串從串口中輸出
{
write_rs=0;
write(fd,"QtEmbedded-4.5.3",16);
}
if(read_rs) //read_rs爲1時讀取,並存在buf
{
read_rs=0;
res=read(fd,buf,10);
buf[res]=0;
emit finished(); //讀完後發一個信號
}
}
printf("Close... ");
tcsetattr(fd,TCSANOW,&oldtio); //從新設置回原來的
close(fd);
quit();
}
經過stopped變量來實現線程控制。
三、主窗口程序設計:
主窗口程序包括線程的啓動與處理,經過信號與槽機制經過write按鍵實現寫串口,經過定時器實現讀串口操做,經過close按鍵實現串口關閉,同時把讀取串口數據進行顯示,其主要程序及分析以下:
1)新建一個mainwindow.h頭文件,內容以下:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include"ui_mainwindow.h" // ui_mainwindow.h 文件爲designer設計
mainwindow.ui文件後,通過make後會生成這個頭文件,
#include"thread.h" //包含線程包頭文件
class MainWindow:public QMainWindow,public Ui::MainWindow //多繼承
{
Q_OBJECT
public:
MainWindow(QWidget *parent=0);
public slots:
void writeThread();
void readThread();
void closeThread();
void display();
private:
Thread *yy;
};
#endif
MainWindow繼承於QMainWindow和MainWindow,即多繼承,對於不是很複雜的程序,用多繼承是一個較好的方法,若是程序較複雜,建議用單繼承,具體緣由待進一步研究,呵呵。
2)新建一個mainwindow.cpp文件,實現程序內容以下:
#include"mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
:QMainWindow(parent)
{
setupUi(this);
yy = new Thread;
yy->start(); //啓動線程
yy->stopped=1; //初始化變量
yy->write_rs=0;
yy->read_rs=0;
QTimer *time = new QTimer(this); //新建定時類
time->start(50); //50ms定時
connect(writeButton,SIGNAL(clicked()),this,SLOT(writeThread()));
//經過信號與槽實現按鍵按下進行寫串口操做
connect(time,SIGNAL(timeout()),this,SLOT(readThread()));
//定時溢出實現讀串口操做
connect(closeButton,SIGNAL(clicked()),this,SLOT(closeThread()));
connect(yy,SIGNAL(finished()),this,SLOT(display())); //接收信號實現顯示
}
void MainWindow::display()
{
textBrowser->setText(yy->buf); //讀到的數據在textBrowser l顯示
}
void MainWindow::writeThread() //寫數據線程槽函數
{
yy->write_rs=1;
}
void MainWindow::readThread() //讀數據線程槽函數
{
yy->read_rs=1;
}
void MainWindow::closeThread() //中止槽函數
{
yy->stopped=0;
}
四、main.cpp函數程序設計:
#include
#include"mainwindow.h"
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
MainWindow mw;
mw.show();
return app.exec();
}
這樣整個linux環境下線程+定時實現的Qt串口編程的程序所有實現,能夠經過串口發送,接收數據實現數據的測試。