Linux下基于QT串口编程测试一
本文博客链接:http://blog.youkuaiyun.com/jdh99,作者:jdh,转载请注明.
环境:
主机:Fedora12
开发软件:QT
目标板:MINI6410
实现功能:
目标板接收PC串口传过来的信息并在终端输出,目标板串口接收信息用SELECT机制
源代码:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QDebug>
#include <QTimer>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/param.h>
#include <QVector>
#include <QByteArray>
#include <QQueue>
#include <QSemaphore>
#include <iostream>
#include <QFile>
#include "QThread"
#include <QtGui>
#include <QMutex>
#include <QtNetwork>
#include <QUdpSocket>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
#include <alsa/asoundlib.h>
#include <QtGui/QMainWindow>
#include <QtGui/QDialog>
#include <QtGui/QPushButton>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QGridLayout>
#include <QTextCodec>
#include <QtGui/QToolButton>
#include <qsocketnotifier.h>
#include <QTimer>
#include <QtNetwork/QUdpSocket>
#include <iostream>
#include <qmessagebox.h>
#include <qstringlist.h>
#include <QtNetwork>
#include <QUdpSocket>
#include <QSound>
#include <QMap>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/soundcard.h>
#include "sys/select.h"
#include "termios.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
};
//端口信息定义
typedef struct _Port_Info
{
int baud_rate;
int port_fd;
char parity;
char stop_bit;
char flow_ctrl;
char data_bits;
}*Port_Info;
//打开串口
int open_port(char *port);
//关闭串口
void close_port(int fd);
//根据波特率获得波特率设置参数
int get_baud_rate(unsigned long baud_rate);
//设置端口参数
int set_port(Port_Info p_info);
//通过串口发送数据,只能写COMPRESS_BYTE长度数据,发送时加文件头"JDH"
int send_data(int fd,char *data,int data_len);
#endif // WIDGET_H
widget.c:
#include "widget.h"
#include "ui_widget.h"
int Fd_Com;
#define COM "/dev/ttySAC1"
char buffer_com[1024 + 10];
char buffer_read_com[1024];
int send_index;
//打开串口
int open_port(char *port)
{
int fd;
if ((fd = open(port,O_RDWR | O_NOCTTY |O_NONBLOCK)) == -1)
{
perror("can not open com port!");
return -1;
}
}
//关闭指定串口
void close_port(int fd)
{
close(fd);
}
//根据波特率获得响应的波特率设置参数
int get_baud_rate(unsigned long baud_rate)
{
switch (baud_rate)
{
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
default:
return -1;
}
}
//设置端口
int set_port(Port_Info p_info)
{
struct termios old_opt,new_opt;
int baud_rate,parity;
memset(&old_opt,0,sizeof(old_opt));
memset(&new_opt,0,sizeof(new_opt));
cfmakeraw(&new_opt);
tcgetattr(p_info->port_fd,&old_opt);
//设置串口波特率
baud_rate = get_baud_rate(p_info->baud_rate);
//修改new_opt结构中的串口输入/输出波特率槽参数
cfsetispeed(&new_opt,baud_rate);
cfsetospeed(&new_opt,baud_rate);
//修改控制模式,保证程序不会占用串口
new_opt.c_cflag |= CLOCAL;
//修改控制模式,使得能够从串口读取输入数据
new_opt.c_cflag |= CREAD;
//设置数据流控制
switch (p_info->flow_ctrl)
{
case '0':
{
//不使用流控制
new_opt.c_cflag &= ~CRTSCTS;
break;
}
case '1':
{
//使用硬件进行流控制
new_opt.c_cflag |= CRTSCTS;
break;
}
case '2':
{
new_opt.c_cflag |= IXON | IXOFF | IXANY;
break;
}
}
//设置数据位
new_opt.c_cflag &= ~CSIZE;
switch (p_info->data_bits)
{
case '5':
{
new_opt.c_cflag |= CS5;
break;
}
case '6':
{
new_opt.c_cflag |= CS6;
break;
}
case '7':
{
new_opt.c_cflag |= CS7;
break;
}
case '8':
{
new_opt.c_cflag |= CS8;
break;
}
default:
{
new_opt.c_cflag |= CS8;
break;
}
}
//设置奇偶校验位
switch (p_info->parity)
{
case '0':
{
//不使用奇偶校验
new_opt.c_cflag &= ~PARENB;
break;
}
case '1':
{
//使用偶校验
new_opt.c_cflag |= PARENB;
new_opt.c_cflag &= ~PARODD;
break;
}
case '2':
{
//使用奇校验
new_opt.c_cflag |= PARENB;
new_opt.c_cflag |= PARODD;
break;
}
}
//设置停止位
if (p_info->stop_bit == '2')
{
new_opt.c_cflag |= CSTOPB;
}
else
{
new_opt.c_cflag &= ~CSTOPB;
}
//修改输出模式,原始数据输出
new_opt.c_oflag *= ~OPOST;
//修改控制字符,读取字符最小个数为1
new_opt.c_cc[VMIN] = 1;
//修改控制字符,读取第一个字符等待等待1 *(1/10)s
new_opt.c_cc[VTIME] = 1;
//如果发生数据溢出,接收数据,但是不再读取
tcflush(p_info->port_fd,TCIFLUSH);
int result;
result = tcsetattr(p_info->port_fd,TCSANOW,&new_opt);
if (result == -1)
{
perror("cannot set the serial port parameters");
return -1;
}
tcgetattr(p_info->port_fd,&old_opt);
return result;
}
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//串口初始化
//打开串口
Fd_Com = open_port(COM);
//设置串口通信参数
struct _Port_Info info;
info.baud_rate = 115200;
info.data_bits = 8;
info.flow_ctrl = 0;
info.port_fd = Fd_Com;
info.stop_bit = 1;
info.parity = 0;
if (set_port(&info) == -1)
{
printf("set com para wrong!!!!!!!!!!!!!");
}
int err = 0;
struct timeval wait_time;
fd_set read_fds;
int len_com = 0;
char *data = "jdh";
int len = write(Fd_Com,data,3);
if (len != 3)
{
//如果出现溢出情况
qDebug() << "yi chu";
tcflush(Fd_Com,TCOFLUSH);
}
while (1)
{
wait_time.tv_sec = 0;
wait_time.tv_usec = 20000;
FD_ZERO(&read_fds);
FD_SET(Fd_Com,&read_fds);
//err = select(Fd_Com + 1,&read_fds,NULL,NULL,&wait_time);
err = select(Fd_Com + 1,&read_fds,NULL,NULL,NULL);
if (err < 0)
{
perror("select fail");
continue;
}
else
{
if (err == 0)
{
//超时返回
//qDebug() << "chao shi";
continue;
}
}
//读取串口声卡
//判断声卡是否允许读,不允许读退出
if (FD_ISSET(Fd_Com,&read_fds))
{
qDebug() << "du qu sheng ka";
//读取串口缓存所有数据
len_com = read(Fd_Com,buffer_read_com,1024);
qDebug() << "read com byte = " << len_com;
QByteArray temp;
temp.append(buffer_read_com,len_com);
qDebug() << temp;
}
}
qDebug() << "end";
}
Widget::~Widget()
{
delete ui;
}
说明:
串口在驱动中有一个缓存区,收到的数据会存放在里面,如果一次发送数据很多,而读取间隔很短,则每次读取都是整个数据包的片段.