Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3537445
  • 博文数量: 864
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10634
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/zytc2009/BigTeam_learning

文章分类

全部博文(864)

文章存档

2023年(1)

2021年(1)

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(69)

2011年(103)

2010年(357)

2009年(283)

2008年(22)

分类: C/C++

2010-12-02 18:13:22

因为Qt编写串口通信程序全程图文讲解系列是很好实现,那只是在windows下面的,可是 在linux下面实现串口的通信并非如此,原因在于QextSerialBase::EventDriven跟 QextSerialBase::Polling这两个事件的区别,EventDriven属于异步,Polling属于同步,在windows下面使用 的是EventDriven很容易实现,只要有数据就会触发一个串口事件,网上说linux下面需要的是Polling,可是还是不行的,只要串口有数据 的时候他会在QByteArray temp = myCom->readAll(); 这句一直读取数据,没能退出,直到断掉串口的时候才能把接受到的串口数据通过 ui->textBrowser->insertPlainText(temp);打印在界面上,一直没能解决这个问题,所以只好采用线程+ 定时实现linux下的Qt串口编程进行设计。

一、安装环境:

:Ubuntu-8.04,内核2.6.24-27-generic,图形

二、软件需求及下地地址:

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,

下载地址:略

三、程序编写过程

程序编程流程:

      先新建一个工程空白工程,再建立Ui文件,通过designer进行Ui界面设计,设计完保存,编译生成ui_mainwindow.h头文件,编写线程头文件及线程处理.cpp文件,建立串口处理头文件及 .cpp文件,最后完成main.cpp文件。

1、           Ui文件的设计:

建立Ui_MainWindow主窗口,在窗口上添加三个QPushButton,分别命名 为closeButton、writeButton、readButton,再添加一个QTextBrowser显示串口接收数据,保存退出,编译一下就 可以生成ui_mainwindow.h文件。

2、线程程序设计:

编写一个线程程序,其不需要进行界面设计,直接实现线程的管理,实现串口的收发工作,其主要程序及说明如下:

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变量来实现线程控制。

3、主窗口程序设计:

主窗口程序包括线程的启动与处理,通过信号与槽机制通过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;

}

4、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串口编程的程序全部实现,可以通过串口发送,接收数据实现数据的测试。

阅读(1781) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~