Qt的线程操作主要有两种 :
一种是直接重写run函数,此时只有run函数内的操作处于线程中,其他定义及函数则还在主线程,会出现跨线程问题.
另一种就是 将工作任务继承自QObject,然后将对象moveToThread实现 工作对象完全工作在线程之中.
本文采用第二种方式实现串口线程操作:
串口工作函数:
1. 继承QOBject
2. 共有槽函数
void updateComCfg(comcfg_t); /* 用于串口配置 */
void startThread(); /* 启动线程 */
void stopThread(); /* 停止线程 */
void writeData(QByteArray);/* 发送数据 */
3. 定义信号
/* 打开成功发送 true,失败 false */
void openError(bool);/* 串口打开异常时,通知主线程进行错误提示 */
void readyread(QByteArray);/* 接收数据时,将数据发送主线程 */
void errOccurred(QString); /* 串口工作过程中异常时,通知主线程进行错误提示,错误情况下自动关闭串口 */
#ifndef UARTWORK_H
#define UARTWORK_H
#include
#include "uartcfg.h"
#include
#include
#include
#include
#include
class uartWork : public QObject {
Q_OBJECT
public:
explicit uartWork(comcfg_t);
~uartWork();
public slots:
void updateComCfg(comcfg_t);
void startThread();
void stopThread();
void writeData(QByteArray);
private slots:
void readyRead();
// void errorString();
void openUart();
void errorOccurred(QSerialPort::SerialPortError error);
void timerOut();
signals:
/* 打开成功发送 true,失败 false */
void openError(bool);
void readyread(QByteArray);
void errOccurred(QString);
private:
bool isConnectFlag;
bool openFlag;
QTimer *rcvDataTimer;
comcfg_t currentCfg;
QSerialPort *currSerial;
QThread *currThread;
QByteArray sendArray;
};
#endif // UARTWORK_H
实现文件:
4. uartWork(comcfg_t cfg)
实现串口初始化,
将串口放入线程
设置串口定时30ms,用于断帧
5. void uartWork::updateComCfg(comcfg_t cfg)
更新串口配置
6. 其他函数
void readyRead(); /* 串口接收回调*/
void openUart(); /* 打开串口 */
void errorOccurred(QSerialPort::SerialPortError error); /* 错误处理 */
void timerOut();/* 超时处理 */
#include "uartwork.h"
uartWork::uartWork(comcfg_t cfg) {
currentCfg.portNum = cfg.portNum;
currentCfg.baudRate = cfg.baudRate;
currentCfg.dataBits = cfg.dataBits;
currentCfg.paritys = cfg.paritys;
currentCfg.stopBits = cfg.stopBits;
currentCfg.flowCtrl = cfg.flowCtrl;
isConnectFlag = false;
currSerial = new QSerialPort();
currSerial->setReadBufferSize(1);
currThread = new QThread();
rcvDataTimer = new QTimer();
this->moveToThread(currThread);
currSerial->moveToThread(currThread);
rcvDataTimer->moveToThread(currThread);
connect(currSerial, &QSerialPort::errorOccurred, this,
&uartWork::errorOccurred);
connect(currSerial, &QSerialPort::readyRead, this, &uartWork::readyRead,
Qt::QueuedConnection);
currThread->start();
rcvDataTimer->setInterval(30);
rcvDataTimer->setTimerType(Qt::PreciseTimer);
connect(rcvDataTimer, &QTimer::timeout, this, &uartWork::timerOut,
Qt::QueuedConnection);
}
uartWork::~uartWork() {
rcvDataTimer->stop();
delete rcvDataTimer;
if (currSerial->isOpen()) {
currSerial->clear();
currSerial->close();
emit openError(false);
}
if (currThread->isRunning()) {
currThread->quit();
while (true == currThread->isRunning())
;
}
currSerial->deleteLater();
currThread->deleteLater();
}
void uartWork::updateComCfg(comcfg_t cfg) {
currentCfg.portNum = cfg.portNum;
currentCfg.baudRate = cfg.baudRate;
currentCfg.dataBits = cfg.dataBits;
currentCfg.paritys = cfg.paritys;
currentCfg.stopBits = cfg.stopBits;
currentCfg.flowCtrl = cfg.flowCtrl;
/* 通知打开串口 */
openUart();
// startThread();
}
void uartWork::startThread() {
if (false == currThread->isRunning()) {
currThread->start();
}
}
void uartWork::stopThread() {
if (currSerial->isOpen()) {
currSerial->clear();
currSerial->close();
emit openError(false);
}
}
void uartWork::timerOut() {
if (sendArray.isEmpty())
return;
rcvDataTimer->stop();
emit readyread(sendArray);
sendArray.clear();
}
void uartWork::readyRead() {
QByteArray data = currSerial->readAll();
if (rcvDataTimer->isActive()) {
rcvDataTimer->stop();
}
if (true == data.isEmpty())
return;
sendArray += data;
rcvDataTimer->start(30);
}
void uartWork::openUart() {
if (currSerial->isOpen()) {
currSerial->clear();
currSerial->close();
}
currSerial->setPortName(QString("COM%1").arg(currentCfg.portNum));
currSerial->setBaudRate(currentCfg.baudRate);
currSerial->setDataBits(currentCfg.dataBits);
currSerial->setParity(currentCfg.paritys);
currSerial->setStopBits(currentCfg.stopBits);
currSerial->setFlowControl(currentCfg.flowCtrl);
openFlag = currSerial->open(QIODevice::ReadWrite);
emit openError(openFlag);
}
void uartWork::writeData(QByteArray data) {
if ((true == currSerial->isOpen()) && (false == data.isEmpty())) {
currSerial->write(data);
}
}
void uartWork::errorOccurred(QSerialPort::SerialPortError error) {
switch ((int)error) {
case 0:
/* 没有错误 */
emit openError(true);
break;
case 1:
/* 打开一个不存在的设备 */
currSerial->close();
emit errOccurred(QString("打开一个不存在的设备!"));
emit openError(false);
break;
case 2:
/* 无权限打开一个 */
currSerial->close();
emit errOccurred(QString("无权限打开设备!"));
emit openError(false);
break;
case 3:
/* 打开一个已经打开的设备 */
emit errOccurred(QString("设备已打开!"));
emit openError(false);
break;
case 7:
/* 写入数据时发生的i/o错误 */
currSerial->close();
emit errOccurred(QString("写数据错误!"));
openUart();
break;
case 8:
/* 读取数据时发生了i/o错误 */
currSerial->close();
emit errOccurred(QString("读数据错误!"));
openUart();
break;
case 9:
/* 设备意外拔出,会发生i/o错误 */
currSerial->close();
emit errOccurred(QString("串口已拔出!"));
emit openError(false);
break;
case 10:
/* 系统不支持或者禁止的操作 */
break;
case 11:
/* 未知错误 */
currSerial->close();
emit errOccurred(QString("发生未知错误!"));
emit openError(false);
break;
case 12:
/*
* 发生了超时错误。
* 此值已在QTserialport 5.2中引入。
*/
// curlSerialPort->close();
// emit errOccurred(QString("发生了超时错误!"));
break;
case 13:
/*
* 此错误发生在执行操作时,该操作只有在设备打开时才能成功执行。
* 此值已在QTserialport 5.2中引入。 */
break;
}
}
7. 串口配置参数
typedef struct {
qint32 portNum; /* 串口号 */
qint32 baudRate; /* 波特率 */
QSerialPort::DataBits dataBits; /* 数据位 */
QSerialPort::Parity paritys; /* 校验位 */
QSerialPort::StopBits stopBits; /* 停止位 */
QSerialPort::FlowControl flowCtrl; /* 流控 */
} comcfg_t;
8. 使用
.h
uartWork *comThread;
slots:
void readFromCom(QByteArray);/* 接收数据 */
signals:
void sendData2Uart(QByteArray); /* 发送数据 */
void upCfg2Uart(comcfg_t);/* 更新串口配置 */
void startWork(comcfg_t);/* 启动线程 */
void closeUart();/* 关闭线程 */
void errorOccurred(QString);/* 错误处理 */
void openSucess(bool);/* 打开结果 */
连接对应的槽:
comThread = new uartWork(currentUartCfg);
connect(comThread, &uartWork::readyread, this, &Widget::readFromCom,
Qt::QueuedConnection);
connect(comThread, &uartWork::openError, this, &Widget::openSucess,
Qt::QueuedConnection);
connect(comThread, &uartWork::errOccurred, this, &Widget::errorOccurred,
Qt::QueuedConnection);
connect(this, &Widget::sendData2Uart, comThread, &uartWork::writeData,
Qt::QueuedConnection);
connect(this, &Widget::upCfg2Uart, comThread, &uartWork::updateComCfg,
Qt::QueuedConnection);
connect(this, &Widget::startWork, comThread, &uartWork::updateComCfg,
Qt::QueuedConnection);
connect(this, &Widget::closeUart, comThread, &uartWork::stopThread,
Qt::QueuedConnection);
发送数据
void sendData2Uart(QByteArray);
接收数据:
void readFromCom(QByteArray);
项目源码: 点击这里
gitee: 点击这里