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, //串口名称,如COM1,COM2
- int baud, //波特率:常用取值:CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800
- int byteSize, //数位大小:可取值7、8;
- int parity, //校验方式:可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITY
- int 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, //串口名称,如COM1,COM2
- int baud, //波特率:常用取值:CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800
- int byteSize, //数位大小:可取值7、8;
- int parity, //校验方式:可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITY
- int 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 Sharing
- NULL, // No Security
- OPEN_EXISTING,// Open existing port only
- // FILE_ATTRIBUTE_NORMAL, // Non Overlapped I/O
- 0, //同步方式
- NULL); // Null for Comm Devices
- if (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 cnt=0;
- 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文库。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |