Chinaunix首页 | 论坛 | 博客
  • 博客访问: 567992
  • 博文数量: 63
  • 博客积分: 533
  • 博客等级: 中士
  • 技术积分: 1146
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-24 17:56
文章分类

全部博文(63)

文章存档

2016年(1)

2014年(23)

2013年(17)

2012年(22)

分类: 嵌入式

2012-10-15 22:44:32

 
下面讲述原理,也可以下载完整实验源码:

前言
QT没有提供串口类,使用的是linux提供的函数。
linux下设备和文件使用一样,用open函数打开串口,设置等都提供了函数的,需要自己组合一下,封装成你要的函数。

1.QT串口发送数据
要使用串口,需先打开串口,封装的函数如下:

int open_port(const char* dev_path)
{
int fd;

//open uart
fd = open(dev_path, O_RDWR|O_NOCTTY|O_NDELAY);
if(fd < 0)
{
perror("open serial port");
return -1;
}
if(fcntl(fd, F_SETFL, 0) < 0)//设置为阻塞模式,后面启动的线程会阻塞,串口有数据才读
perror("fcntl F_SETFL\n");
/*if(isatty(STDIN_FILENO) == 0)//再次验证是否为终端设备,我用的刷卡器,屏蔽了这个,不然会失败
{
perror("standard inpput is not a terminal device");
}*/

return fd;
}

接下来需要设置串口的波特率、校验、结束位等,封装的函数如下:

int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits)
{
struct termios new_cfg, old_cfg;
int speed;
int returnvalue;

returnvalue = tcgetattr(fd, &old_cfg);//save current uart configure
if(returnvalue < 0)
{
perror("tcgetattr:tcsetattr()1");
return -1;
}

new_cfg = old_cfg;//直接获取串口的所有数据到新配置,省去了一些参数的手动设置
cfmakeraw(&new_cfg);//config as orignal mode: recevice byte one by one
new_cfg.c_cflag &= ~CSIZE;//clear c_cflag

switch(baud_rate)
{
case 2400:
speed = B2400;break;
case 4800:
speed = B4800;break;
case 9600:
speed = B9600;break;
case 19200:
speed = B19200;break;
case 38400:
speed = B38400;break;
default:
case 115200:
speed = B115200;break;
}
cfsetispeed(&new_cfg, speed);//set in baud_rate
cfsetospeed(&new_cfg, speed);//set out baud_rate;

switch(data_bits)//set data bits
{
case 7:
new_cfg.c_cflag |= CS7;break;
default:
case 8:
new_cfg.c_cflag |= CS8;break;
}

switch(parity)//set parity
{
default:
case 's':
case 'S':
{
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_cflag &= ~INPCK;
}break;

case 'o':
case 'O':
{
new_cfg.c_cflag |= (PARODD | PARENB);
new_cfg.c_cflag |= INPCK;
}break;

case 'e':
case 'E':
{
new_cfg.c_cflag |= PARENB;
new_cfg.c_cflag &= ~PARODD;
new_cfg.c_cflag |= INPCK;
}break;

case 'n':
case 'N':
{
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_cflag &= ~CSTOPB;
}break;

}

switch(stop_bits)//set stop bits
{
default:
case 1:
new_cfg.c_cflag &= ~CSTOPB;break;
case 2:
new_cfg.c_cflag |= CSTOPB;break;
}

//set wait time and min recevice byte
new_cfg.c_cc[VTIME] = 0;
new_cfg.c_cc[VMIN] = 1;

tcflush(fd, TCIFLUSH);//清除数据

returnvalue = tcsetattr(fd, TCSANOW, &new_cfg);//激活配置
if(returnvalue < 0)
{
perror("tcsetattr:tcsetattr()2");
return -1;
}

return 0;
}


发送数据:

write(fd_com, buff, strlen(buff));//发送



2.QT线程编程
接收数据需要用一个线程,比较方便。
新建一个类,继承于QThread,实现其中的run虚函数就大功告成, 用的时候创建该类的实例,调用它的start方法即可。但是run函数使用时有一点需要注意,即在其中不能创建任何gui线程(诸如新建一个QWidget或者QDialog)。如果要想通过新建的线程实现一个gui的功能,那么就需要通过使用线程间的通信来实现。
自己实现run函数,start()函数不用自己写了哈。

.h文件如下:

#ifndef RECEIVETHREAD_H
#define RECEIVETHREAD_H

#include <QThread>

class ReceiveThread : public QThread
{
Q_OBJECT
public:
explicit ReceiveThread(QObject *parent = 0);
void run();
void enStopFlag();
void enBaudChanged_flag();

int fd;
int stop_flag;
char buff[100];
int baudChanged_flag;

signals:
void sendbuff(QString );

public slots:

};

#endif // RECEIVETHREAD_H



run函数如下:

void ReceiveThread::run()
{
qDebug()<<"Receive thread started";

int count_receive=0, c=0;
QString data;

memset(buff, 0, 100);
data.clear();

while(stop_flag)
{
c = read(fd, buff, 100);

if(baudChanged_flag)
{
data.clear();
memset(buff, 0, 100);
count_receive = 0;
baudChanged_flag = 0;
continue ;
}

if(c >= 0)
data += buff;
else continue;

memset(buff, 0, 100);
count_receive += c;
if(count_receive < 14)
continue;

data = data.mid(1, 10);
emit sendbuff(data);

data.clear();
count_receive = 0;
memset(buff, 0, 100);
}

qDebug()<<"Receive thread exited";
}


在mainwindow里面申请一个线程对象,thread->start(),线程就开始监听串口了。

3.QT串口接收数据
上面的线程开始监听了,只要串口设置对了,就可以读串口的数据了,上面程序是收到14个才发送给我的程序用。
我用来读卡的,所以有一些处理。

4.ARM串口收发方便调试的接法
ID读卡器波特率9600,无校验码,停止位1,出口只有TXD和RXD和GND。

读卡器用PC的USB供电
将ARM的GND和PC的GND连接,全部共地;
将读卡器的TXD接到ARM的RXD,读卡器将读到的卡号发给ARM;
将ARM的TXD接到PC的RXD,ARM将你设置的内容发给PC;
这样就可以在ARM上显示读取的卡号,在PC上显示ARM给出的调试信息,主要是同时验证程序的收发是否正确。

下载完整实验源码

接法如图:

 
 

5.线程的结束
有时候需要结束线程,但是如果设置为读串口数据为阻塞模式,则不能立即结束线程,要换个方法,如下:
kill线程 某线程->terminate();

kill线程参考资料:http://qimo601.iteye.com/blog/1287279

以下内容引用自参考资料:(begin到end)

以上代码简单,没有必要做过多的讲解,但是其中的“thread->terminate(); ”有必要讲解下,terminate()函数的调用便不会立刻终止线程,因为线程的何时终止取决于系统的调度策略,所在在之后又调用了wait()函数是线程阻塞等待直到退出或者超时。

最后加以一点就是在.pro文件中加入一行代码才能成功运行:

CONFIG+=thread

转自:http://avny.blog.163.com/blog/static/2101802782012991126278/

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