利用QtRO解决QSerialPort跨线程调用问题

这篇具有很好参考价值的文章主要介绍了利用QtRO解决QSerialPort跨线程调用问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

 文章来源地址https://www.toymoban.com/news/detail-516413.html

一、关于QT多线程串口通信问题

二、QtRo介绍

三、串口控制光源

3.1接口

3.2 服务端

3.3 客户端


 

一、关于QT串口跨线程使用问题

     在机器视觉项目中经常使用串口通信,如光源控制。当串口的创建和读写不在同一个线程时,qt会提示不能跨线程使用的警告,此时很有可能吞并指令或者接收不到数据的情况。有人提出了使用moveToThread+信号槽的方式使得串口的操作在同一个线程中,

https://www.zhihu.com/question/3151

最近在学习RPC通信,所以想了想是否可以通过进程间通信的方式来解决此问题。

二、QtRo介绍

Qt Remote Object简称QtRO,这是Qt5.9以后官方推出来的新模块,专门用于进程间通信(IPC)。在这之前,要实现进程间通信有多种方式,这里就不做介绍了,而Qt官方推出的这个新模块是基于Socket来封装的,使用起来非常方便,兼容LPC和RPC。LPC即Local Process Communication,而RPC是指Remote Process Communication,两者都属于IPC。QtRO能够工作于这两种不同的模式:如果用于LPC,则QtRO使用QLocalSocket;如果是用于RPC,则使用QTcpSocket。对于一个Qt开发者来说,如果项目中涉及到进程间通信,那么直接使用现成的模块进行开发, 莫过于是最好的选择,集成度高,代码量少。

 

三、串口控制光源

https://blog.csdn.net/luoyayun361/article/details/91588654

参考上述博客,自己实现了光源的控制,通过进程间通信的方式可以避免串口多线程问题。

3.1接口

首先定义接口文件 commoninterface.rep

class CommonInterface
{
    SIGNAL(measurePressed())

    SLOT(int deviceConnect())
    SLOT(int deviceDisconnect())
    SLOT(int isConnected())
    SLOT(void writeLight(int bottomLight, int coaxialLight))
    SLOT(void writeGreenLed(bool isOn))
    SLOT(void writeRedLed(bool isOn))
}

 

3.2 服务端

pro文件加入

QT       += remoteobjects
QT       += serialport

REPC_SOURCE  += \
    ../../Reps/commoninterface.rep
 

#ifndef VMDEVICEINTERFACE_H
#define VMDEVICEINTERFACE_H

#include <QObject>

#include "rep_commoninterface_source.h"
class QSerialPort;
class CommonInterface : public CommonInterfaceSource
{
    Q_OBJECT
public:
    explicit CommonInterface(QObject *parent = nullptr);

public Q_SLOTS:
    int deviceConnect() override;
    int deviceDisconnect() override;
    int isConnected() override;
    void writeLight(int bottomLight, int coaxialLight) override;
    void writeGreenLed(bool isOn) override;
    void writeRedLed(bool isOn) override;

signals:
    void sigReceiveMsg(const QString &msg);
    void sigSendLog(const QString &msg);

private slots:
    void slot_ReadData();

private:
    int write(const QString &cmd);

private:
    QSerialPort *m_serialPort;
    bool m_lightResponsed = false;
};

#endif // VMDEVICEINTERFACE_H
#include "VMDeviceInterface.h"
#include <QDebug>
#include <QSerialPort>

CommonInterface::CommonInterface(QObject *parent):
    CommonInterfaceSource(parent)
{
    m_serialPort = new QSerialPort();
    connect(m_serialPort, &QSerialPort::readyRead,
            this, &CommonInterface::slot_ReadData);
}

int CommonInterface::deviceConnect()
{
    m_serialPort->setPortName("COM1");
    m_serialPort->setBaudRate(19200);
    m_serialPort->setDataBits(static_cast<QSerialPort::DataBits>(8));
    m_serialPort->setStopBits(static_cast<QSerialPort::StopBits>(1));

    if(m_serialPort->open(QIODevice::ReadWrite))
    {
        emit sigSendLog("The serial port is in read/write mode");
        qDebug() << "The serial port is in read/write mode";
        return 0;
    }
    else
    {
        QString errorStr = m_serialPort->errorString();
        emit sigSendLog("Serial port open exception:" + errorStr);
        qDebug() << "Serial port open exception:" + errorStr;
        m_serialPort->clearError();
        return -1;
    }
    writeLight(50, 50);
    return 0;
}

int CommonInterface::deviceDisconnect()
{
    writeLight(0, 0);
    m_serialPort->close();
    m_serialPort->deleteLater();
    return 0;
}

int CommonInterface::isConnected()
{
    return m_serialPort->isOpen();
}

void CommonInterface::writeLight(int bottomLight, int coaxialLight)
{
    QString cmd;
    cmd.append("42");
    cmd.append(QString("%1").arg(coaxialLight, 2, 16, QChar('0')));
    cmd.append("00");
    cmd.append("00");
    cmd.append(QString("%1").arg(bottomLight, 2, 16, QChar('0')));
    cmd.append("45");
    cmd.append("2a");
    write(cmd);
}

void CommonInterface::writeGreenLed(bool isOn)
{
    QString cmd = (isOn == true) ?  QString("B201") : QString("B200");
    write(cmd);
}

void CommonInterface::writeRedLed(bool isOn)
{
    QString cmd = (isOn == true) ? QString("B101") : QString("B100");
    write(cmd);
}

void CommonInterface::slot_ReadData()
{
    const QByteArray info = m_serialPort->readAll();
    emit sigSendLog("readyRead:" + info.toHex());
    qDebug() << "readyRead:" + info.toHex();
    if("26" == info.toHex())
    {
        emit measurePressed();
    }
    if("4f4b" == info.toHex())
    {
        m_lightResponsed = true;
    }
}

int CommonInterface::write(const QString &cmd)
{
    if(!m_serialPort->isOpen())
    {
        emit sigSendLog("Failed to send, the serial port is not open");
//        qCritical() << "Failed to send, the serial port is not open";
        return -1;
    }
    emit sigSendLog("cmd: " + cmd);
//    qDebug() << "cmd: " + cmd;

    QByteArray cmdByteArray = QByteArray::fromHex(cmd.toUtf8());
    int len = m_serialPort->write(cmdByteArray);

    emit sigSendLog("write length: " + QString::number(len));
//    if(!m_serialPort->waitForBytesWritten(3 * 1000))
//    {
//        QString errorStr = m_serialPort->errorString();
//        emit sigSendLog("Command sending exception:" + errorStr);
//        qCritical() << "Command sending exception:" + errorStr;
//        m_serialPort->clearError();
//        return -1;
//    }
    return 0;
}

ui界面

#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QMainWindow>

namespace Ui
{
    class MainWindow;
}
class CommonInterface;
class QRemoteObjectHost;
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    CommonInterface *m_pInterface = nullptr;
    QRemoteObjectHost *m_pHost = nullptr;
};

#endif // MAINWINDOW_H
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDebug>
#include "VMDeviceInterface.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_pHost = new QRemoteObjectHost(this);
    m_pHost->setHostUrl(QUrl("local:interfaces"));
    m_pInterface = new CommonInterface(this);
    m_pHost->enableRemoting(m_pInterface);
    connect(m_pInterface, &CommonInterface::sigSendLog, this,
            [ = ](const QString & msg)
    {
        ui->textEdit->append(msg);
    });
    m_pInterface->deviceConnect();
}

MainWindow::~MainWindow()
{
    m_pInterface->deviceDisconnect();
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{

}

3.3 客户端

pro文件加入

QT       += remoteobjects
QT       += concurrent

REPC_REPLICA   += \
    ../../Reps/commoninterface.rep
 

UI界面

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui
{
    class MainWindow;
}
QT_END_NAMESPACE

class QRemoteObjectNode;
class CommonInterfaceReplica;

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_bSlider_sliderReleased();
    void on_cSlider_sliderReleased();
    void on_btnThreadSend_clicked();

    void on_btnL1_clicked();

    void on_btnL2_clicked();

    void on_btnL3_clicked();

    void on_btnSend_clicked();

private:
    Ui::MainWindow *ui;
    QRemoteObjectNode      *m_pRemoteNode = nullptr;
    CommonInterfaceReplica *m_pInterface  = nullptr;
};
#endif // MAINWINDOW_H
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDebug>
#include <QtConcurrent>

#include "rep_CommonInterface_replica.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->textEdit->append(QString("..."));

    m_pRemoteNode = new QRemoteObjectNode(this);
    bool b = m_pRemoteNode->connectToNode(QUrl("local:interfaces"));
    if(b)
    {
        ui->textEdit->append(QString("connect true"));
    }
    else
    {
        ui->textEdit->append(QString("connect flase"));
    }
    m_pInterface = m_pRemoteNode->acquire<CommonInterfaceReplica>();

    connect(m_pInterface, &CommonInterfaceReplica::measurePressed,
            this, [ = ]()
    {
        ui->textEdit->append(QString("measurePressed"));
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_bSlider_sliderReleased()
{
    ui->textEdit->append(tr("%1,%2")
                         .arg(ui->bSlider->value())
                         .arg( ui->cSlider->value()));
    m_pInterface->writeLight(ui->bSlider->value(),
                             ui->cSlider->value());
}

void MainWindow::on_cSlider_sliderReleased()
{
    ui->textEdit->append(tr("%1,%2")
                         .arg(ui->bSlider->value())
                         .arg( ui->cSlider->value()));
    m_pInterface->writeLight(ui->bSlider->value(),
                             ui->cSlider->value());
}

void Delay_MSec(unsigned int msec)
{
    QEventLoop loop;
    QTimer::singleShot(msec, &loop, SLOT(quit()));
    loop.exec();
}

void MainWindow::on_btnThreadSend_clicked()
{
    auto runFun = [ = ]()
    {
        int ms = ui->spinBox->value();

        m_pInterface->writeLight(1, 200);
        Delay_MSec(ms);
        m_pInterface->writeLight(200, 1);
        Delay_MSec(ms);
        m_pInterface->writeLight(50, 50);
    };
//    std::thread thread(runFun);
    QtConcurrent::run(runFun);
}

void MainWindow::on_btnL1_clicked()
{
    m_pInterface->writeLight(1, 200);
}

void MainWindow::on_btnL2_clicked()
{
    m_pInterface->writeLight(200, 1);
}

void MainWindow::on_btnL3_clicked()
{
    m_pInterface->writeLight(50, 50);
}


void MainWindow::on_btnSend_clicked()
{
    int ms = ui->spinBox->value();
    m_pInterface->writeLight(1, 200);
    Delay_MSec(ms);
    m_pInterface->writeLight(200, 1);
    Delay_MSec(ms);
    m_pInterface->writeLight(50, 50);
}

 

 

到了这里,关于利用QtRO解决QSerialPort跨线程调用问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包