目录
一、关于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_OBJECTpublic: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_NAMESPACEclass QRemoteObjectNode;
class CommonInterfaceReplica;class MainWindow : public QMainWindow
{Q_OBJECTpublic: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);
}