Qt之串口设计-线程实现(十二)

打印 上一主题 下一主题

主题 762|帖子 762|积分 2286

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,详细实现如下。
  1. #include <QThread>
  2. #include <stdio.h>
  3. #include <windows.h>
  4. //缓冲区大小
  5. #define BUF_SIZE    1000
  6. class comt4hread : public QThread
  7. {  
  8.     Q_OBJECT
  9. public:
  10.     comt4hread();
  11.     ~comt4hread(){}
  12.     bool start_flag;
  13.     bool save_flag;
  14.     QByteArray filebuf;
  15.     QByteArray sendbuf;
  16.     const char *ComName;
  17.     int BaudValue;
  18.     int BitValue;
  19.     int ParitySelt;
  20.     int StopSelt;
  21. protected:
  22.     HANDLE OpenSerial(const char *com, //串口名称,如COM1,COM2
  23.         int baud,       //波特率:常用取值:CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800
  24.         int byteSize,   //数位大小:可取值7、8;
  25.         int parity,     //校验方式:可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITY
  26.         int stopBits);
  27.     void run(void);
  28.     void ProData(QByteArray);
  29. };
复制代码
在上面代码中,必要添加头文件#include <Windows.h>,该函数的详细用法可以参考微软MS的官方文档Win32 应用 |Microsoft 学习,里面比力详细。
2.相干功能函数

该线程类的实现:首先在构造函数初始化相干变量;然后通过OpenSerial函数完成对串口的一系列设置,包罗波特率、校验位等;最后启动线程run后,在while循环中实现对串口的读(ReadFile函数)、写(WriteFile函数)。代码如下(示例):
  1. #include "com4thread.h"
  2. comt4hread::comt4hread(){
  3.     start_flag = false;
  4.     ComName = "COM4";
  5. }
  6. HANDLE comt4hread::OpenSerial(const char *com, //串口名称,如COM1,COM2
  7.     int baud,       //波特率:常用取值:CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800
  8.     int byteSize,   //数位大小:可取值7、8;
  9.     int parity,     //校验方式:可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITY
  10.     int stopBits)   //停止位:ONESTOPBIT、ONE5STOPBITS、TWOSTOPBITS;
  11. {
  12.     DCB dcb;
  13.     BOOL b = FALSE;
  14.     COMMTIMEOUTS CommTimeouts;
  15.     HANDLE comHandle = INVALID_HANDLE_VALUE;
  16.     //打开串口
  17.     WCHAR wszClassName[10];
  18.     memset(wszClassName, 0, sizeof(wszClassName));
  19.     MultiByteToWideChar(CP_ACP, 0, com, int(strlen(com)+1), wszClassName,
  20.         sizeof(wszClassName) / sizeof(wszClassName[0]));
  21.     comHandle = CreateFile(wszClassName,            //串口名称
  22.         GENERIC_READ | GENERIC_WRITE,      //可读、可写
  23.         0,            // No Sharing
  24.         NULL,         // No Security
  25.         OPEN_EXISTING,// Open existing port only
  26. //        FILE_ATTRIBUTE_NORMAL,            // Non Overlapped I/O
  27.         0, //同步方式
  28.         NULL);        // Null for Comm Devices
  29.     if (INVALID_HANDLE_VALUE == comHandle) {
  30.         qDebug() << "CreateFile fail.";
  31.         return comHandle;
  32.     }
  33.     // 设置读写缓存大小
  34.     b = SetupComm(comHandle, BUF_SIZE, BUF_SIZE);
  35.     if (!b)
  36.         qDebug() << "SetupComm fail.";
  37.     //设定读写超时
  38.     CommTimeouts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
  39.     CommTimeouts.ReadTotalTimeoutMultiplier = 0;//读时间系数
  40.     CommTimeouts.ReadTotalTimeoutConstant = 0;//读时间常量
  41.     CommTimeouts.WriteTotalTimeoutMultiplier = 1;//写时间系数
  42.     CommTimeouts.WriteTotalTimeoutConstant = 1;//写时间常量
  43.     b = SetCommTimeouts(comHandle, &CommTimeouts); //设置超时
  44.     if (!b)
  45.         qDebug() << "SetCommTimeouts fail.";
  46.     //设置串口状态属性
  47.     GetCommState(comHandle, &dcb); // 获取当前
  48.     dcb.BaudRate = ulong(baud);           // 波特率
  49.     dcb.ByteSize = uchar(byteSize);       // 每个字节有位数
  50.     dcb.Parity   = uchar(parity);         // 无奇偶校验位
  51.     dcb.StopBits = uchar(stopBits);       // 一个停止位
  52.     b = SetCommState(comHandle, &dcb);//设置
  53.     if (!b)
  54.         qDebug() << "SetCommState fail.";
  55.     return comHandle;
  56. }
  57. void comt4hread::run(void)
  58. {
  59.     BOOL err = FALSE;
  60.     DWORD wRLen = 0;
  61.     DWORD wWLen = 0;
  62.     char buf[BUF_SIZE] = {0};
  63.     HANDLE comHandle = INVALID_HANDLE_VALUE;//串口句柄
  64.     QByteArray tempbuf;
  65.     //打开串口
  66.     comHandle = OpenSerial(ComName, CBR_115200, 8, NOPARITY, ONESTOPBIT);
  67.     //comHandle = OpenSerial(ComName, BaudValue, BitValue, ParitySelt, StopSelt);
  68.     qDebug() << comHandle;
  69.     if (INVALID_HANDLE_VALUE == comHandle) {
  70.         qDebug() << "OpenSerial COM fail!";
  71.         return;
  72.     }
  73.     qDebug() << "Open COM Successfully!";
  74.     //循环接收消息,收到消息后将消息内容
  75.     while(start_flag){
  76.         wRLen = 0;
  77.         //读串口消息
  78.         err = ReadFile(comHandle, buf, sizeof(buf)-1, &wRLen, NULL);
  79.         if (err && wRLen > 0) //读成功并且数据大小大于0
  80.         {
  81.             tempbuf.append(buf, int(wRLen));
  82.             if(save_flag)
  83.                 filebuf.append(tempbuf);
  84.             //处理数据
  85.             ProData(tempbuf);
  86.             tempbuf.clear();
  87.         }
  88.         //写串口消息
  89.         if(!sendbuf.isEmpty()){
  90.             err = WriteFile(comHandle, sendbuf, size_t(sendbuf.size()), &wWLen, NULL);
  91.             if (!err)
  92.                 qDebug() << "SendData_WriteFile fail.";
  93.             sendbuf.clear();
  94.         }
  95.     }
  96. }
复制代码
3.用户使用

创建完上面的线程类后,用户必要调用/使用它,首先在构造函数初始化串口、定时器相干变量,然后通过定时器实时获取串口,当串口有效时,启动串口,详细寄义实现如下。
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. MainWindow::MainWindow(QWidget *parent) :
  4.     QMainWindow(parent),
  5.     ui(new Ui::MainWindow){
  6.     ui->setupUi(this);
  7.     /****串口初始化*****/
  8.     Initcomthread();   
  9.     /****定时器初始化****/
  10.     InitTimerEvent();
  11. }
  12. MainWindow::~MainWindow()
  13. {
  14.     delete ui;   
  15. }
  16. void MainWindow::Initcomthread(void)
  17. {
  18.     comth = new comt4hread();
  19.     comth->start_flag = false;
  20.     comth->save_flag = false;
  21.     //comth->start(QThread::HighPriority);
  22.     //connect(this, SIGNAL(comconfig(QStringList)), comth, SLOT(comconfig(QStringList)));
  23. }
  24. void MainWindow::InitTimerEvent(void)
  25. {
  26.     timecnt = 0;
  27.     ftimer_flag = true;
  28.     show_1s_flag = true;
  29.     m_pluseTimeid = startTimer(100); // 100毫秒事件处理
  30. }
  31. //发送数据
  32. void MainWindow::on_sendButton_clicked()
  33. {   
  34.     QByteArray temp = ui->textEdit->toPlainText().toLatin1();   
  35.     comth->sendbuf.append(temp);
  36. //    comth->send_flag = true;
  37.     ui->listWidgetRecv->addItem("本地发送数据:" + temp.toHex(' ').toUpper());
  38.     ui->listWidgetRecv->setCurrentRow(ui->listWidgetRecv->count() - 1);
  39. }
  40. void MainWindow::timerEvent(QTimerEvent *t)
  41. {
  42.     if(t->timerId() == m_pluseTimeid) // 100毫秒事件处理
  43.     {
  44.         static quint8 cnt=0;
  45.         cnt++;
  46.         if(cnt == 10){
  47.             //查找可用的串口
  48.             if(ftimer_flag)
  49.             {
  50.                 if(!(ui->PortBox->currentText().isEmpty()))
  51.                 {
  52.                     ui->lineEdit_6->setText("获取可用串口");
  53.                     ui->lineEdit_6->setStyleSheet("color:red;");
  54.                     ftimer_flag = false;
  55.                     show_1s_flag = true;
  56.                 }
  57.                 else
  58.                 {
  59.                     ui->lineEdit_6->setText(QString::number(timecnt));
  60.                     timecnt++;
  61.                     foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
  62.                     {
  63.                         QSerialPort serialtemp;
  64.                         serialtemp.setPort(info);
  65.                         if(serialtemp.open(QIODevice::ReadWrite))
  66.                         {
  67.                             ui->PortBox->addItem(serialtemp.portName());
  68.                             serialtemp.clear();
  69.                             serialtemp.close();
  70.                         }
  71.                     }
  72.                 }
  73.             }
  74.             else
  75.             {
  76.                 if(ui->PortBox->currentText().isEmpty()){
  77.                     ftimer_flag = true;
  78.                     timecnt = 0;
  79.                 }
  80.                 show_1s_flag = true;
  81.             }
  82.             cnt = 0;
  83.         }
  84.     }
  85. }
  86. void MainWindow::on_PortBox_activated(const QString &arg1)
  87. {
  88.     if(arg1.isEmpty())
  89.         return;
  90.     comth->ComName = ui->PortBox->currentText().toUtf8();
  91.     comth->BaudValue = ui->BaudBox->currentText().toInt();
  92.     comth->BitValue = ui->BitNumBox->currentText().toInt();
  93.     comth->ParitySelt = ui->ParityBox->currentText().toInt();
  94.     comth->StopSelt = ui->StopBox->currentText().toInt();
  95.     comth->start(QThread::HighPriority);
  96. }
  97. void MainWindow::on_clear_clicked()
  98. {
  99.     ui->listWidgetRecv->clear();
  100. }
复制代码
4.结果演示

软件搜刮到没有串口时,开始计时。

有串口时,选择相应串口,Qt输出栏提示Open COM Successful!

5.拓展应用-实时刷新

一样平常我们工业上使用串口,为了实现对数据实时采集、并通过曲线显示出来。这时我们一样平常采取的是,先在线程中将串口收到的数据举行剖析处置惩罚ProData,然后将剖析出来的结果值通过变量传递给主界面上,让其知晓,然后通过主窗口的定时器或者信号槽函数显示在UI界面上。
假如是要绘制曲线,可以参考博文Qt之第三方库QCustomPlot使用(二)-CSDN博客,了解曲线绘制的特性及使用方法。

总结

博文中相应的工程代码Qt-Case.zip 使用Qt开发软件举行编的例程,为博文提供案例-CSDN文库。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大连密封材料

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表