//ui_mainwindow.h

#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QLabel>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>
#include <QtGui/QWidget>

QT_BEGIN_NAMESPACE

class Ui_MainWindow
{
public:
QWidget *centralWidget;
QPushButton *writeButton;
QPushButton *readButton;
QPushButton *closeButton;
QLabel *dis_label;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;

void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(600, 400);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
writeButton = new QPushButton(centralWidget);
writeButton->setObjectName(QString::fromUtf8("writeButton"));
writeButton->setGeometry(QRect(100, 210, 75, 23));
readButton = new QPushButton(centralWidget);
readButton->setObjectName(QString::fromUtf8("readButton"));
readButton->setGeometry(QRect(240, 210, 75, 23));
closeButton = new QPushButton(centralWidget);
closeButton->setObjectName(QString::fromUtf8("closeButton"));
closeButton->setGeometry(QRect(390, 210, 75, 23));
dis_label = new QLabel(centralWidget);
dis_label->setObjectName(QString::fromUtf8("dis_label"));
dis_label->setGeometry(QRect(200, 90, 191, 16));
MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 600, 19));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);

retranslateUi(MainWindow);

QMetaObject::connectSlotsByName(MainWindow);
} // setupUi

void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8));
writeButton->setText(QApplication::translate("MainWindow", "PushButton", 0, QApplication::UnicodeUTF8));
readButton->setText(QApplication::translate("MainWindow", "PushButton", 0, QApplication::UnicodeUTF8));
closeButton->setText(QApplication::translate("MainWindow", "PushButton", 0, QApplication::UnicodeUTF8));
dis_label->setText(QApplication::translate("MainWindow", "TextLabel", 0, QApplication::UnicodeUTF8));
} // retranslateUi

};

namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_MAINWINDOW_H


//thread.h
#ifndef THREAD_H
#define THREAD_H
#include<QThread>

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.cpp
#include"thread.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h> //串口用到的
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>

#define BAUDRATE B9600
#define RS_DEVICE "/dev/ttyS0" //串口0
//#define RS_DEVICE "/dev/ttySAC1" //串口1

Thread::Thread()
{} //析构

void Thread::run() //这就是线程的具体工作了
{
int fd,c=0,res;
struct termios oldtio,newtio; //termios结构是用来保存波特率、字符大小等

printf("start.../n");

fd=open(RS_DEVICE,O_RDWR|O_NOCTTY); //以读写方式打开串口。不控制TTY
if(fd<0)
{
perror("error");
exit(1); //失败退出
}

printf("Open.../n");

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.1",16); //向串口中写入字符,通过串口调试助手可看到QtEmbedded-4.5.1这个字符
}

if(read_rs) //read_rs为1时读取,并存在buf
{
read_rs=0;
res=read(fd,buf,10); //读取串口的数据到buf
buf[res]=0;
emit finished(); //读完后发一个信号
}

}
printf("Close.../n");
tcsetattr(fd,TCSANOW,&oldtio); //重新设置回原来的
close(fd);
quit();
}

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include<QtGui>
#include"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.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;

connect(writeButton,SIGNAL(clicked()),this,SLOT(writeThread())); //信号与槽
connect(readButton,SIGNAL(clicked()),this,SLOT(readThread()));
connect(closeButton,SIGNAL(clicked()),this,SLOT(closeThread()));
connect(yy,SIGNAL(finished()),this,SLOT(display())); //前面线程读完了不是发一个信号么,这个信号就是发到这个槽
}

void MainWindow::display()
{
dis_label->setText(yy->buf); //读到的在dis_label显示,dis_label就是我们前面designer放的标签,显示buf中的内容
}

void MainWindow::writeThread() //前面线程都是根据stopped、write_rs、read_rs的状态来工作的^_^
{
yy->write_rs=1;
}

void MainWindow::readThread()
{
yy->read_rs=1;
}

void MainWindow::closeThread()
{
yy->stopped=0;
}

//main.cpp
#include<QApplication>
#include"mainwindow.h"

int main(int argc,char *argv[])
{
QApplication app(argc,argv);
MainWindow mw;
mw.show();
return app.exec();
}