目录
文章来源地址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);
}
文章来源:https://www.toymoban.com/news/detail-516413.html
到了这里,关于利用QtRO解决QSerialPort跨线程调用问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!