**

QT多线程接收串口数据

**
1.前言
QT多线程的使用,和绝大数人一样,犯了错误(请查阅Qt开发人员( Bradley T. Hughes)Blog中的文章 you are-doing-it-wrong介绍)。为了解决问题,网上查阅学习了几十篇文章,基本都是错误的使用方法,或者不完整,未能给予正确的引导。
为方便后来学习者,少走弯路,于是自己动手写了一下程序,过程不再赘述,只以完整的案例进行教学,内部注释较多,可供大家阅读、思考。

2.功能作用
使用多线程,避免上位机软件与单片机等硬件设备高速通讯时,造成软件界面假死、丢包等现象。同时对串口进行了简单的封装,方便调用。本文提供了完整的源代码,方便测试。有较详细的注释方便阅读、思考。编译环境为QT5.8.0,Qt Creator4.2.1

3.软件测试效果


4.基本步骤
(1)pro文件添加QT5自带的头文件

QT       += serialport

(2)serialworker.h头文件

#include "serialworker.h"SerialWorker::SerialWorker(QSerialPort *ser, QObject *parent) : QObject(parent),serial(ser)
{}
QString SerialWorker::ByteArrayToHexString(QByteArray data)
{QString ret(data.toHex().toUpper());int len = ret.length()/2;qDebug()<<"收到字节长度为:"<<len;for(int i=1;i<len;i++){ret.insert(2*i+i-1," ");}return ret;
}void SerialWorker::doDataReciveWork()
{    QByteArray buffer = serial->readAll();// 2.进行数据处理QString result = ByteArrayToHexString(buffer);qDebug() <<  "子线程收到数据:" << result << "线程ID:" << QThread::currentThreadId();// 3.将结果发送到主线程emit sendResultToGui(result);
}

(3)mainwindow.h文件

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setWindowTitle("子线程读串口");this->setMinimumSize(600,248);this->setMaximumSize(1200,496);InitSerialPortName();//1.新建串口处理子线程SerialWorker *ser = new SerialWorker(&serial_1);ser->moveToThread(&serialThread_1);// 2.连接信号和槽QString s;connect(&serialThread_1, &QThread::finished, ser, &QObject::deleteLater);           // 线程结束,自动删除对象connect(&serial_1, &QSerialPort::readyRead, ser, &SerialWorker::doDataReciveWork); // 主线程通知子线程接收数据的信号connect(ser, &SerialWorker::sendResultToGui, this, &MainWindow::handleResults);    // 主线程收到数据结果的信号//  connect(ser,SIGNAL(sendResultToGui(QString)), this, SLOT(handleResults(QString)));     //主线程收到数据结果的信号写法2// 3.开始运行子线程serialThread_1.start();                   // 线程开始运行
}MainWindow::~MainWindow()
{serialThread_1.quit();serialThread_1.wait();delete ui;
}void MainWindow::InitSerialPortName()
{// 清空下拉框ui->box_portName->clear();//通过QSerialPortInfo查找可用串口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){QString showName = info.portName();qDebug() << showName+info.description();ui->box_portName->addItem(showName);}//波特率QStringList baudrateList;baudrateList<<"4800"<<"9600"<<"19200"<<"38400"<<"57600"<<"115200";ui->box_baudrate->addItems(baudrateList);//添加下拉列表选项ui->box_baudrate->setCurrentText("115200");//界面中初始值//    ui->box_baudrate->setView(new QListView(this));//该设置是配合qss的,不然item行高设置没效果//数据位QStringList databitList;databitList<<"5"<<"6"<<"7"<<"8";ui->box_dataBits->addItems(databitList);ui->box_dataBits->setCurrentText("8");
//      ui->box_dataBits->setView(new QListView(this));//校验位QStringList parityList;parityList<<"无"<<"奇"<<"偶";ui->box_parityBit->addItems(parityList);ui->box_parityBit->setCurrentText("No");
//      ui->box_parityBit->setView(new QListView(this));//停止位QStringList stopbitList;stopbitList<<"1"<<"2";ui->box_stopBit->addItems(stopbitList);ui->box_stopBit->setCurrentText("1");
//      ui->box_stopBit->setView(new QListView(this));//流控制
//        QStringList flowctrlList;
//        flowctrlList<<"No"<<"Hardware"<<"Software";
//        ui->boxFlowControl->addItems(flowctrlList);
//        ui->boxFlowControl->setCurrentText("No");
      ui->boxFlowControl->setView(new QListView(this));
}void MainWindow::on_btn_openPort_clicked()
{if(ui->btn_openPort->text()==QString("打开串口")){//设置串口名QString portName = (ui->box_portName->currentText()).split(":").at(0);qDebug() <<"当前打开串口为:"<<portName;serial_1.setPortName(portName);//设置波特率serial_1.setBaudRate(ui->box_baudrate->currentText().toInt());//设置停止位if(ui->box_stopBit->currentText() == "1")serial_1.setStopBits(QSerialPort::OneStop);else if(ui->box_stopBit->currentText() == "2")serial_1.setStopBits(QSerialPort::TwoStop);//设置数据位数if(ui->box_dataBits->currentText() == "8")serial_1.setDataBits(QSerialPort::Data8);else if(ui->box_dataBits->currentText() == "7")serial_1.setDataBits(QSerialPort::Data7);else if(ui->box_dataBits->currentText() == "6")serial_1.setDataBits(QSerialPort::Data6);else if(ui->box_dataBits->currentText() == "5")serial_1.setDataBits(QSerialPort::Data5);//设置奇偶校验if(ui->box_parityBit->currentText() == "无")serial_1.setParity(QSerialPort::NoParity);else if(ui->box_parityBit->currentText() == "偶")serial_1.setParity(QSerialPort::EvenParity);else if(ui->box_parityBit->currentText() == "奇")serial_1.setParity(QSerialPort::OddParity);//        //设置流控制
//        serial_1.setFlowControl(QSerialPort::NoFlowControl);//打开串口if(!serial_1.open(QIODevice::ReadWrite)){QMessageBox::about(NULL, "提示", "无法打开串口!");return;}//下拉菜单控件失能ui->box_portName->setEnabled(false);ui->box_baudrate->setEnabled(false);ui->box_dataBits->setEnabled(false);ui->box_parityBit->setEnabled(false);ui->box_stopBit->setEnabled(false);ui->btn_openPort->setText(QString("关闭串口"));}else{//关闭串口serial_1.close();//下拉菜单控件使能ui->box_portName->setEnabled(true);ui->box_baudrate->setEnabled(true);ui->box_dataBits->setEnabled(true);ui->box_parityBit->setEnabled(true);ui->box_stopBit->setEnabled(true);ui->btn_openPort->setText(QString("打开串口"));}
}void MainWindow::on_btn_clearText_clicked()
{ui->browser_dataReceive->clear();
}void MainWindow::handleResults(const QString &result)
{qDebug() <<  "主线程收到结果数据:" << result << "线程ID:" << QThread::currentThreadId();//从界面中读取以前收到的数据QString oldString = ui->browser_dataReceive->toPlainText()+'\n';oldString = oldString + QString(result);//清空以前的显示ui->browser_dataReceive->clear();//重新显示ui->browser_dataReceive->append(oldString);
}

(4)mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setWindowTitle("子线程读串口");this->setMinimumSize(600,248);this->setMaximumSize(1200,496);InitSerialPortName();//1.新建串口处理子线程SerialWorker *ser = new SerialWorker(&serial_1);ser->moveToThread(&serialThread_1);// 2.连接信号和槽QString s;connect(&serialThread_1, &QThread::finished, ser, &QObject::deleteLater);           // 线程结束,自动删除对象connect(&serial_1, &QSerialPort::readyRead, ser, &SerialWorker::doDataReciveWork); // 主线程通知子线程接收数据的信号connect(ser, &SerialWorker::sendResultToGui, this, &MainWindow::handleResults);    // 主线程收到数据结果的信号//  connect(ser,SIGNAL(sendResultToGui(QString)), this, SLOT(handleResults(QString)));     //主线程收到数据结果的信号写法2// 3.开始运行子线程serialThread_1.start();                   // 线程开始运行
}MainWindow::~MainWindow()
{serialThread_1.quit();serialThread_1.wait();delete ui;
}void MainWindow::InitSerialPortName()
{// 清空下拉框ui->box_portName->clear();//通过QSerialPortInfo查找可用串口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){QString showName = info.portName();qDebug() << showName+info.description();ui->box_portName->addItem(showName);}//波特率QStringList baudrateList;baudrateList<<"4800"<<"9600"<<"19200"<<"38400"<<"57600"<<"115200";ui->box_baudrate->addItems(baudrateList);//添加下拉列表选项ui->box_baudrate->setCurrentText("115200");//界面中初始值//    ui->box_baudrate->setView(new QListView(this));//该设置是配合qss的,不然item行高设置没效果//数据位QStringList databitList;databitList<<"5"<<"6"<<"7"<<"8";ui->box_dataBits->addItems(databitList);ui->box_dataBits->setCurrentText("8");
//      ui->box_dataBits->setView(new QListView(this));//校验位QStringList parityList;parityList<<"无"<<"奇"<<"偶";ui->box_parityBit->addItems(parityList);ui->box_parityBit->setCurrentText("No");
//      ui->box_parityBit->setView(new QListView(this));//停止位QStringList stopbitList;stopbitList<<"1"<<"2";ui->box_stopBit->addItems(stopbitList);ui->box_stopBit->setCurrentText("1");
//      ui->box_stopBit->setView(new QListView(this));//流控制
//        QStringList flowctrlList;
//        flowctrlList<<"No"<<"Hardware"<<"Software";
//        ui->boxFlowControl->addItems(flowctrlList);
//        ui->boxFlowControl->setCurrentText("No");
      ui->boxFlowControl->setView(new QListView(this));
}void MainWindow::on_btn_openPort_clicked()
{if(ui->btn_openPort->text()==QString("打开串口")){//设置串口名QString portName = (ui->box_portName->currentText()).split(":").at(0);qDebug() <<"当前打开串口为:"<<portName;serial_1.setPortName(portName);//设置波特率serial_1.setBaudRate(ui->box_baudrate->currentText().toInt());//设置停止位if(ui->box_stopBit->currentText() == "1")serial_1.setStopBits(QSerialPort::OneStop);else if(ui->box_stopBit->currentText() == "2")serial_1.setStopBits(QSerialPort::TwoStop);//设置数据位数if(ui->box_dataBits->currentText() == "8")serial_1.setDataBits(QSerialPort::Data8);else if(ui->box_dataBits->currentText() == "7")serial_1.setDataBits(QSerialPort::Data7);else if(ui->box_dataBits->currentText() == "6")serial_1.setDataBits(QSerialPort::Data6);else if(ui->box_dataBits->currentText() == "5")serial_1.setDataBits(QSerialPort::Data5);//设置奇偶校验if(ui->box_parityBit->currentText() == "无")serial_1.setParity(QSerialPort::NoParity);else if(ui->box_parityBit->currentText() == "偶")serial_1.setParity(QSerialPort::EvenParity);else if(ui->box_parityBit->currentText() == "奇")serial_1.setParity(QSerialPort::OddParity);//        //设置流控制
//        serial_1.setFlowControl(QSerialPort::NoFlowControl);//打开串口if(!serial_1.open(QIODevice::ReadWrite)){QMessageBox::about(NULL, "提示", "无法打开串口!");return;}//下拉菜单控件失能ui->box_portName->setEnabled(false);ui->box_baudrate->setEnabled(false);ui->box_dataBits->setEnabled(false);ui->box_parityBit->setEnabled(false);ui->box_stopBit->setEnabled(false);ui->btn_openPort->setText(QString("关闭串口"));}else{//关闭串口serial_1.close();//下拉菜单控件使能ui->box_portName->setEnabled(true);ui->box_baudrate->setEnabled(true);ui->box_dataBits->setEnabled(true);ui->box_parityBit->setEnabled(true);ui->box_stopBit->setEnabled(true);ui->btn_openPort->setText(QString("打开串口"));}
}void MainWindow::on_btn_clearText_clicked()
{ui->browser_dataReceive->clear();
}void MainWindow::handleResults(const QString &result)
{qDebug() <<  "主线程收到结果数据:" << result << "线程ID:" << QThread::currentThreadId();//从界面中读取以前收到的数据QString oldString = ui->browser_dataReceive->toPlainText()+'\n';oldString = oldString + QString(result);//清空以前的显示ui->browser_dataReceive->clear();//重新显示ui->browser_dataReceive->append(oldString);
}

(5)serialworker.cpp文件

#include "serialworker.h"SerialWorker::SerialWorker(QSerialPort *ser, QObject *parent) : QObject(parent),serial(ser)
{}
QString SerialWorker::ByteArrayToHexString(QByteArray data)
{QString ret(data.toHex().toUpper());int len = ret.length()/2;qDebug()<<"收到字节长度为:"<<len;for(int i=1;i<len;i++){ret.insert(2*i+i-1," ");}return ret;
}void SerialWorker::doDataReciveWork()
{    QByteArray buffer = serial->readAll();// 2.进行数据处理QString result = ByteArrayToHexString(buffer);qDebug() <<  "子线程收到数据:" << result << "线程ID:" << QThread::currentThreadId();// 3.将结果发送到主线程emit sendResultToGui(result);
}

QT多线程接收串口数据相关推荐

  1. Qt中接收串口数据不完整、分段的解决方法

    场景: 最近在串口通信时碰到了一个问题,向485串口发送指定报文,会收到一条关于压力数值的数据.但将其qDebug打印出来却发现数据被分成了两部分依次打印,之后通过验证确定了问题出在readyRead ...

  2. 51UWB单片机连接ESP8266实现Wifi接收串口数据

    UWB定位需要电脑读取UWB基站的串口数据来读取距离信息,用wifi连接可以实现远程接收串口数据方便连接.这里记录一下如何让51UWB单片机接入WiFi模块ESP8266. 前置条件: 单片机完成基站 ...

  3. serialport接收串口数据_C#串口操作类,包括串口读写操作

    串口进行操作的类,其中包括写和读操作,类可设置串口参数.设置接收函数.打开串口资源.关闭串口资源,操作完成后,一定要关闭串口.接收串口数据事件.接收数据出错事件.获取当前全部串口.把字节型转换成十六进 ...

  4. java swing 串口_ComTest 接收串口数据,并显示在文本框内,通过JavaSwing实现 Develop 265万源代码下载- www.pudn.com...

    文件名称: ComTest下载  收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 3157 KB 上传时间: 2016-09-21 下载次数: 0 提 供 者: 韩坤 ...

  5. 串口通信——接收串口数据并处理(C语言)

    本文主要内容包含:  1.接收串口数据程序的编程逻辑示意图:  2.接收串口数据程序要用到的通用函数模块(可直接引用,无需更改):  3.接收串口数据程序的示例. 1.接收串口数据程序的编程逻辑示意图 ...

  6. 使用iocomp中iplot控件实现接收串口数据并显示曲线

    概述:Iocomp 是一个强大的工业控件.适用于vb/vc/vs.net/Delphi/BCB(windows/linux).囊括了常见的工业控件. 本例使用简单iocomp控件中的一个简单iplot ...

  7. simulink接收串口数据_基于Unity串口通信的解决方案

    思路有三种,等下我会详细介绍. 后面的博客详细介绍是我收录两年前写的博客,现在我已经没有往串口方向进行开发了,所以只能将一些思路分享给大家. ​ ​ 解决方式一:将Unity串口通信数据模块(接收与发 ...

  8. 如何在QT中读取串口数据

    总是能在别人的博客中学到太多太多,谢谢各位对知识的无私共享,谢谢大家 前言 去年我使用Qt编写串口通信程序时,将自己的学习过程写成了教程(Qt编写串口通信程序全程图文讲解),但是由于时间等原因,我只实 ...

  9. 如何接收串口数据_UART IDLE 中断使用接收不定长串口数据

    前言 在串口通信应用中,我们常使用接受和发送中断,相信大家都不陌生.这里有个非常有用的中断可能被大家所忽略,即总线IDLE中断.当一帧数据传输结束之后,总线会维持高电平状态,此时,就可以触发MCU的I ...

最新文章

  1. C#编程(五十三)----------字典DictionaryTKey,TValue
  2. prometheus下载慢_Prometheus + Grafana 监控 SpringBoot
  3. 开关电源雷击浪涌整改_大佬多年经验总结,开关电源EMI整改策略
  4. FixedSizeList的使用
  5. Cocostudio 1.6 下载地址
  6. how does gateway framework treat default system flag in customizing
  7. centos7 docker
  8. Maximum Subarray leetcode java
  9. 为什么html中li浮动,相对定位下的绝对定位下的li为什么不能浮动??
  10. 找到恶意软件包:Go 语言生态系统中的供应链攻击是怎样的?
  11. java 通过反射获取数组
  12. Himall商城文件帮助类IOHelper(1)
  13. linux修改文件:E212 can't open file for writing
  14. 基于unity3D的趣味桌球游戏开发
  15. 【Matlab】如何规范地编写一个MATLAB函数文件
  16. “我们“App功能介绍
  17. Web安全第 01 讲:渗透测试方法论
  18. 路飞学城-Python爬虫实战密训-第1章
  19. i3 10100和i5 10400哪个好
  20. 将直播链接放入微信公众号

热门文章

  1. 有了MVC,为什么还要DDD?
  2. 给WordPress增加QQ邮件列表订阅
  3. 魅蓝e2 android n,魅族Flyme公布近期更新预告 用户体验仍是发力重点
  4. spaa的交互式绘图_spaa如何快速入门
  5. 如何发掘孩子的兴趣点
  6. repeater中的item databound事件的具体发生过程
  7. 扫描件电子版怎么弄?手机也能轻松拿捏
  8. OMNET++ INET官方实例(2)
  9. php substring的用法,substring方法怎么使用
  10. java中substring用法_java中substring的用法