Qt将串口放入线程中

 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: 点击这里

 

 

 

你可能感兴趣的:(Qt学习,多线程,Qt串口,串口)