Linux下基于QT串口编程测试一
本文博客链接:http://blog.csdn.net/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
#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; }
说明:
串口在驱动中有一个缓存区,收到的数据会存放在里面,如果一次发送数据很多,而读取间隔很短,则每次读取都是整个数据包的片段.