行业网站策划方案,wordpress网站建设教程,html网页教程,wordpress 点赞插件Qt开发 系列文章 - Serial-port#xff08;十二#xff09; 目录
前言
一、SerialPort
二、实现方式
1.创建类
2.相关功能函数
3.用户使用
4.效果演示
5.拓展应用-实时刷新
总结 前言
Qt作为一个跨平台的应用程序开发框架#xff0c;在串口编程方面提供了方便易用…Qt开发 系列文章 - Serial-port十二 目录
前言
一、SerialPort
二、实现方式
1.创建类
2.相关功能函数
3.用户使用
4.效果演示
5.拓展应用-实时刷新
总结 前言
Qt作为一个跨平台的应用程序开发框架在串口编程方面提供了方便易用的API使得开发者能够轻松实现基于串口通信的各种应用。
Qt框架中提供的一个串口通讯类QtSerialPort它属于Qt自带的模块类专门用于进行串行通信使用时只需要在工程文件pro内添加QT serialport即可这种实现方式封装程度高、使用简单与Qt框架集成紧密利用Qt的信号与槽机制进行事件处理采用但给我的感觉在一些高速数据处理时不是很好用。因此本文推荐采用Windows API调用相关串口功能函数用于从文件或设备中读取数据。 一、SerialPort
在Qt平台中调用window相关API例如CreatFile、readFile、writeFile等函数以实现串口通讯并采用C语言实现。
二、实现方式
本文将采用线程实现对串口数据的收发创建一个线程类将该类作为主窗口的私有变量使用。
在该线程类中通过Windows串口被抽象为文件对串口的读、写实际上就是对文件的读写。
1.创建类
在Qt项目上创建一个串口类属于线程public QThread具体实现如下。
#include QThread
#include stdio.h
#include windows.h
//缓冲区大小
#define BUF_SIZE 1000
class comt4hread : public QThread
{ Q_OBJECT
public:comt4hread();~comt4hread(){}bool start_flag;bool save_flag;QByteArray filebuf;QByteArray sendbuf;const char *ComName;int BaudValue;int BitValue;int ParitySelt;int StopSelt;
protected:HANDLE OpenSerial(const char *com, //串口名称如COM1COM2int baud, //波特率常用取值CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800int byteSize, //数位大小可取值7、8int parity, //校验方式可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITYint stopBits);void run(void);void ProData(QByteArray);
};在上面代码中需要添加头文件#include Windows.h该函数的具体用法可以参考微软MS的官方文档Win32 应用 |Microsoft 学习里面比较详细。
2.相关功能函数
该线程类的实现首先在构造函数初始化相关变量然后通过OpenSerial函数完成对串口的一系列设置包括波特率、校验位等最后启动线程run后在while循环中实现对串口的读ReadFile函数、写WriteFile函数。代码如下示例
#include com4thread.h
comt4hread::comt4hread(){start_flag false;ComName COM4;
}
HANDLE comt4hread::OpenSerial(const char *com, //串口名称如COM1COM2int baud, //波特率常用取值CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800int byteSize, //数位大小可取值7、8int parity, //校验方式可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITYint stopBits) //停止位ONESTOPBIT、ONE5STOPBITS、TWOSTOPBITS
{DCB dcb;BOOL b FALSE;COMMTIMEOUTS CommTimeouts;HANDLE comHandle INVALID_HANDLE_VALUE;//打开串口WCHAR wszClassName[10];memset(wszClassName, 0, sizeof(wszClassName));MultiByteToWideChar(CP_ACP, 0, com, int(strlen(com)1), wszClassName,sizeof(wszClassName) / sizeof(wszClassName[0]));comHandle CreateFile(wszClassName, //串口名称GENERIC_READ | GENERIC_WRITE, //可读、可写0, // No SharingNULL, // No SecurityOPEN_EXISTING,// Open existing port only
// FILE_ATTRIBUTE_NORMAL, // Non Overlapped I/O0, //同步方式NULL); // Null for Comm Devicesif (INVALID_HANDLE_VALUE comHandle) {qDebug() CreateFile fail.;return comHandle;}// 设置读写缓存大小b SetupComm(comHandle, BUF_SIZE, BUF_SIZE);if (!b)qDebug() SetupComm fail.;//设定读写超时CommTimeouts.ReadIntervalTimeout MAXDWORD;//读间隔超时CommTimeouts.ReadTotalTimeoutMultiplier 0;//读时间系数CommTimeouts.ReadTotalTimeoutConstant 0;//读时间常量CommTimeouts.WriteTotalTimeoutMultiplier 1;//写时间系数CommTimeouts.WriteTotalTimeoutConstant 1;//写时间常量b SetCommTimeouts(comHandle, CommTimeouts); //设置超时if (!b)qDebug() SetCommTimeouts fail.;//设置串口状态属性GetCommState(comHandle, dcb); // 获取当前dcb.BaudRate ulong(baud); // 波特率dcb.ByteSize uchar(byteSize); // 每个字节有位数dcb.Parity uchar(parity); // 无奇偶校验位dcb.StopBits uchar(stopBits); // 一个停止位b SetCommState(comHandle, dcb);//设置if (!b)qDebug() SetCommState fail.;return comHandle;
}
void comt4hread::run(void)
{BOOL err FALSE;DWORD wRLen 0;DWORD wWLen 0;char buf[BUF_SIZE] {0};HANDLE comHandle INVALID_HANDLE_VALUE;//串口句柄QByteArray tempbuf;//打开串口comHandle OpenSerial(ComName, CBR_115200, 8, NOPARITY, ONESTOPBIT);//comHandle OpenSerial(ComName, BaudValue, BitValue, ParitySelt, StopSelt);qDebug() comHandle;if (INVALID_HANDLE_VALUE comHandle) {qDebug() OpenSerial COM fail!;return;}qDebug() Open COM Successfully!;//循环接收消息收到消息后将消息内容while(start_flag){wRLen 0;//读串口消息err ReadFile(comHandle, buf, sizeof(buf)-1, wRLen, NULL);if (err wRLen 0) //读成功并且数据大小大于0{tempbuf.append(buf, int(wRLen));if(save_flag)filebuf.append(tempbuf);//处理数据ProData(tempbuf);tempbuf.clear();}//写串口消息if(!sendbuf.isEmpty()){err WriteFile(comHandle, sendbuf, size_t(sendbuf.size()), wWLen, NULL);if (!err)qDebug() SendData_WriteFile fail.;sendbuf.clear();}}
}
3.用户使用
创建完上面的线程类后用户需要调用/使用它首先在构造函数初始化串口、定时器相关变量然后通过定时器实时获取串口当串口有效时启动串口具体含义实现如下。
#include mainwindow.h
#include ui_mainwindow.h
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow){ui-setupUi(this);/****串口初始化*****/Initcomthread(); /****定时器初始化****/InitTimerEvent();
}
MainWindow::~MainWindow()
{delete ui;
}
void MainWindow::Initcomthread(void)
{comth new comt4hread();comth-start_flag false;comth-save_flag false;//comth-start(QThread::HighPriority);//connect(this, SIGNAL(comconfig(QStringList)), comth, SLOT(comconfig(QStringList)));
}
void MainWindow::InitTimerEvent(void)
{timecnt 0;ftimer_flag true;show_1s_flag true;m_pluseTimeid startTimer(100); // 100毫秒事件处理
}
//发送数据
void MainWindow::on_sendButton_clicked()
{ QByteArray temp ui-textEdit-toPlainText().toLatin1(); comth-sendbuf.append(temp);
// comth-send_flag true;ui-listWidgetRecv-addItem(本地发送数据 temp.toHex( ).toUpper());ui-listWidgetRecv-setCurrentRow(ui-listWidgetRecv-count() - 1);
}
void MainWindow::timerEvent(QTimerEvent *t)
{if(t-timerId() m_pluseTimeid) // 100毫秒事件处理{static quint8 cnt0;cnt;if(cnt 10){//查找可用的串口if(ftimer_flag){if(!(ui-PortBox-currentText().isEmpty())){ui-lineEdit_6-setText(获取可用串口);ui-lineEdit_6-setStyleSheet(color:red;);ftimer_flag false;show_1s_flag true;}else{ui-lineEdit_6-setText(QString::number(timecnt));timecnt;foreach(const QSerialPortInfo info, QSerialPortInfo::availablePorts()){QSerialPort serialtemp;serialtemp.setPort(info);if(serialtemp.open(QIODevice::ReadWrite)){ui-PortBox-addItem(serialtemp.portName());serialtemp.clear();serialtemp.close();}}}}else{if(ui-PortBox-currentText().isEmpty()){ftimer_flag true;timecnt 0;}show_1s_flag true;}cnt 0;}}
}
void MainWindow::on_PortBox_activated(const QString arg1)
{if(arg1.isEmpty())return;comth-ComName ui-PortBox-currentText().toUtf8();comth-BaudValue ui-BaudBox-currentText().toInt();comth-BitValue ui-BitNumBox-currentText().toInt();comth-ParitySelt ui-ParityBox-currentText().toInt();comth-StopSelt ui-StopBox-currentText().toInt();comth-start(QThread::HighPriority);
}
void MainWindow::on_clear_clicked()
{ui-listWidgetRecv-clear();
}
4.效果演示
软件搜索到没有串口时开始计时。 有串口时选择相应串口Qt输出栏提示Open COM Successful 5.拓展应用-实时刷新
一般我们工业上使用串口为了实现对数据实时采集、并通过曲线显示出来。这时我们一般采取的是先在线程中将串口收到的数据进行解析处理ProData然后将解析出来的结果值通过变量传递给主界面上让其知晓然后通过主窗口的定时器或者信号槽函数显示在UI界面上。
如果是要绘制曲线可以参考博文Qt之第三方库QCustomPlot使用二-CSDN博客了解曲线绘制的特性及使用方法。 总结
博文中相应的工程代码Qt-Case.zip 利用Qt开发软件进行编的例程为博文提供案例-CSDN文库。