当使用单线程时,对于在UI界面中需要进行逻辑运算时,界面会发生卡顿甚至无响应情况,这时需要使用多线程技术,将串口数据采集以及数据处理代码放入子线程中运行。代码如下:
主线程:
#include "widget.h"
#include "ui_widget.h"
//QSerialPort serial; //串口对象定义
//Pulling PullingData; //结构体对象定义,PullingData用来储存拉力数据
QByteArray buffer; //定义额外的缓冲区,用来缓存串口发送来的数据
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
/*创建线程对象*/
QThread *thread = new QThread; //创建子线程对象
serialportmanager *worker = new serialportmanager(); //创建工作类对象
worker->moveToThread(thread); //将工作 放入子线程中
/*连接信号和槽*/
connect(worker,&serialportmanager::newData_send,this,&Widget::newData_receive);
connect(worker,&serialportmanager::newStringdata_send,this,&Widget::newStringdata_receive);
/*启动线程*/
thread->start();
/*使工作的对象开始工作,槽函数连接*/
connect(ui->openBt,&QPushButton::clicked,worker,&serialportmanager::serialport_set);
connect(ui->closeBt,&QPushButton::clicked,worker,&serialportmanager::serialport_close);
setWindowTitle("薄膜双向拉伸仪拉力采集系统");
QStringList serialNamePort; //将串口名放入QStringList列表中
serialPort = new QSerialPort(this); //创建一个新的QSerialPort对象,并将其指针赋值给serialPort变量
//初始化QChart
initChart();
//connect(serialPort,SIGNAL(readyRead()),this,SLOT(serialPortReadyRead_Slot())); //当串行端口有数据可读时,readyRead信号会被发射,马上读取串口缓冲区数据
foreach (const QSerialPortInfo &info , QSerialPortInfo::availablePorts()) {
serialNamePort<<info.portName();
}
ui->serialCb->addItems(serialNamePort); //显示连接的可用串口
timer = new QTimer(); //创建一个定时器对象,用于运行时间计时
TimeRecord = new QTime(0,0,0);
ui->lcdNumber->setDigitCount(6);
ui->lcdNumber->setMode(QLCDNumber::Dec); //十进制
ui->lcdNumber->setSegmentStyle(QLCDNumber::Flat); //扁平显示
ui->lcdNumber_2->setDigitCount(6);
ui->lcdNumber_2->setMode(QLCDNumber::Dec); //十进制
ui->lcdNumber_2->setSegmentStyle(QLCDNumber::Flat); //扁平显示
ui->lcdNumber_3->setDigitCount(8); //设置位数
ui->lcdNumber_3->setSegmentStyle(QLCDNumber::Flat);
ui->lcdNumber_3->display(TimeRecord->toString("hh:mm:ss"));
//timer->setInterval(1); //定时周期
connect(timer,SIGNAL(timeout()),this,SLOT(updateTime())); //测量时间记录定时器的槽函数,每隔1秒触发一次
}
Widget::~Widget()
{
delete ui;
}
/*确认是否关闭程序*/
void Widget::closeEvent(QCloseEvent *ev){
QMessageBox::Button btn = QMessageBox::question(this,"关闭窗口","您确定要关闭程序吗?");
if(btn==QMessageBox::Yes){
ev->accept();
}
else{
ev->ignore();
}
}
子线程
#include "serialportmanager.h"
//Pulling PullingData; //结构体对象定义,PullingData用来储存拉力数据
serialportmanager::serialportmanager(QObject *parent): QObject(parent)
{
serialPort = new QSerialPort(); //创建一个新的QSerialPort对象,并将其指针赋值给serialPort变量
//QStringList serialNamePort; //将串口名放入QStringList列表中
connect(serialPort, &QSerialPort::readyRead, this, &serialportmanager::serialPortReadyRead_Slot); //使serialPortReadyRead_Slot自动读取数据
}
/*串口参数设置*/
void serialportmanager::serialport_set()
{
/*将接收到的串口属性写入串口*/
serialPort->setPortName("COM3");
serialPort->setBaudRate(QSerialPort::Baud115200); //试验时,直接设置窗口
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setParity(QSerialPort::NoParity);
if (serialPort->open(QIODevice::ReadWrite)) {
qDebug() << "Serial port opened successfully";
} else {
qDebug() << "Failed to open serial port";
}
}
void serialportmanager::serialPortReadyRead_Slot()
{
QByteArray buf = serialPort->readAll(); //读取串口信息
buffer.append(buf);
int index;
while((index=buffer.indexOf("\r\n"))!=-1)
{
QByteArray message = buffer.left(index);
buffer.remove(0,index+2);
QStringList floatStrings = QString::fromUtf8(message).split(",");
//emit newStringdata_send(floatStrings);
if(floatStrings.size()==2)
{
float float_Vol[2];
for(int i=0;i<2;i++)
{
float_Vol[i] = floatStrings[i].toFloat();//转化为浮点数
}
PullingData.channel_1 = float_Vol[0];
PullingData.channel_2 = float_Vol[1];
qDebug()<<PullingData.channel_1<<PullingData.channel_2;
emit newData_send(PullingData.channel_1,PullingData.channel_2);
}
else
{
qDebug()<<"INVALID DATA FORMAT";
}
}
}
//关闭串口
void serialportmanager::serialport_close()
{
if (serialPort->isOpen()) {
serialPort->close();
serialPort->clear();
qDebug() << "Serial port closed";
}
}
运行结果如下,测量数据流畅显示