您的位置:首页 > 健康 > 养生 > 诚信网站 互联网建站_html个人主页_推广衣服的软文_杭州seo网站建设靠谱

诚信网站 互联网建站_html个人主页_推广衣服的软文_杭州seo网站建设靠谱

2024/12/22 11:40:08 来源:https://blog.csdn.net/weixin_38416696/article/details/144503845  浏览:    关键词:诚信网站 互联网建站_html个人主页_推广衣服的软文_杭州seo网站建设靠谱
诚信网站 互联网建站_html个人主页_推广衣服的软文_杭州seo网站建设靠谱

Qt 框架下 使用modbus协议

一,使用Qt原生的 QModbusClient ,比如QModbusTcpClient

1,因为modbus的读写 需要在同一个线程中,所以需要在主线程中利用moveToThread的方式,将业务逻辑封装到 子线程中。

2,modbus封装

#pragma once
#include <QObject>
#include <QModbusTcpClient>
#include <QCoreApplication>
#include <qdebug.h>namespace Device {class Modbus:public QObject{Q_OBJECTpublic:Modbus(QObject*parent): QObject(parent){}protected:bool modbusRead(QModbusTcpClient * modbusMaster,int serverAddress, QModbusDataUnit::RegisterType type, int newStartAddress, quint16 newValueCount, QList<quint16> &array, bool warning){QModbusDataUnit readUnit(type, newStartAddress, newValueCount);QModbusReply *reply = modbusMaster->sendReadRequest(readUnit, serverAddress);if(reply == nullptr){qDebug()<<QStringLiteral("modbusRead 无效请求");return false;}while (!reply->isFinished()){QCoreApplication::processEvents();}if (reply->error() == QModbusDevice::NoError){QModbusDataUnit resultUnit = reply->result();for (int i = 0; i < static_cast<int>(resultUnit.valueCount()); ++i) {array.append(resultUnit.value(i));}return true;}else{qDebug()<<QStringLiteral("modbusRead reply %1").arg(reply->errorString());return false;}}bool modbusWrite(QModbusTcpClient * modbusMaster,int serverAddress, QModbusDataUnit::RegisterType type, int newStartAddress, quint16 newValueCount, QList<quint16> array, bool warning){QModbusDataUnit writeUnit(type, newStartAddress, newValueCount);for(int i = 0; i < newValueCount; i++)writeUnit.setValue(i, array.value(i));QModbusReply *reply = modbusMaster->sendWriteRequest(writeUnit, serverAddress);if(reply == nullptr){qDebug()<<QStringLiteral("modbusWrite 无效请求");return false;}while (!reply->isFinished()){QCoreApplication::processEvents();}if (reply->error() == QModbusDevice::NoError){return true;}else{qDebug()<<QStringLiteral("modbusWrite reply %1").arg(reply->errorString());return false;}}};
}

3,继承上述类,封装业务逻辑,以压力传感器为例。将功能放到槽函数中。

class ModbusWorkerPressure:public Modbus{
Q_OBJECT
public:explicit ModbusWorkerPressure(Modbus*parent= nullptr);~ModbusWorkerPressure() override;public slots:void open();void close();void zero();signals:void siStatus(int type,int result);private:QModbusTcpClient *modbusClient{nullptr};bool bOpened{false};bool bExit{false};
};
ModbusWorkerPressure::ModbusWorkerPressure(Modbus *parent): Modbus(parent)  {}ModbusWorkerPressure::~ModbusWorkerPressure() {}void ModbusWorkerPressure::close() {bExit = true;DELAY(500);if (bOpened) {modbusClient->disconnectDevice();}if (modbusClient != nullptr) {modbusClient->deleteLater();}
}void ModbusWorkerPressure::open() {modbusClient = new QModbusTcpClient(this);modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "10.10.10.2");modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);modbusClient->setTimeout(500);if (modbusClient->connectDevice()) {DELAY(500);while (!bExit) {QList<quint16> list;int32_t pressure=0;if(modbusRead(modbusClient,1,QModbusDataUnit::HoldingRegisters,0x0000,0x0002,list,false)){int result = 0;result =static_cast<int32_t>(list[1])<<16|list[0];pressure = result;//单位gDataManager::Instance().setCurPressure(pressure);//能读出数据 认为连接成功static bool execute = false;if (!execute) {bOpened = true;emit siStatus(0, 0);execute = true;}}DELAY(5);}} else {emit siStatus(0, -1);bOpened = false;}
}void ModbusWorkerPressure::zero() {QList<quint16> list{0x0001};if (!modbusWrite(modbusClient,1, QModbusDataUnit::HoldingRegisters, 0x0002, 0x0001, list, false)) {LOGE(u8"压力传感器  清零失败!");}
}

4, 主线程 使用moveToThread 将上述业务线程进行封装,然后主线程中 用信号,进行触发

bool PressureSensor::open(){workerThread = new QThread();modbusWorker = new ModbusWorkerPressure();modbusWorker->moveToThread(workerThread);QObject::connect(workerThread, &QThread::started, modbusWorker, &ModbusWorkerPressure::open);QObject::connect(this, &PressureSensor::siClose, modbusWorker, &ModbusWorkerPressure::close);QObject::connect(this, &PressureSensor::siZero, modbusWorker, &ModbusWorkerPressure::zero);QObject::connect(modbusWorker, &ModbusWorkerPressure::siStatus, [&](int type, int result) {if (type == 0) {if (result == 0) {bOpened = true;} else {bOpened = false;}}});workerThread->start();return true;}bool PressureSensor::zero() {if(!bOpened)return false;emit siZero();return true;}

5,此种方式 优点就是Qt原生框架,但是缺点是 这种方式是异步的方式,想要做到同步调用,比如轴系运动中,需要自己去同步,试过 QEventLoop的方式,但是不行,会丢失事件。

二,第三方库 libmodbus

1,编译及下载

Libmodbus在win11下的编译与VS2019下的运行_libmodbus vs2019-CSDN博客

2,写bool

 auto home  = [&](bool flag){const int read_regAddress = 55;const int numBits = 1;uint16_t coilStatus[numBits];int rc;{QMutexLocker locker(&mutex);rc = modbus_read_registers(modbusContext,read_regAddress,numBits,coilStatus);}if (rc == -1) {LOGE(QString("goHome Failed to read Modbus coils %1").arg(modbus_strerror(errno)).toUtf8());}else {uint16_t value = coilStatus[0];if(flag){value|=0x80;}else{value&=0xFF7F;}{QMutexLocker locker(&mutex);rc = modbus_write_register(modbusContext, read_regAddress, value);}if (rc == -1) {LOGE(QString("goHome Failed to write Modbus coil %1").arg(modbus_strerror(errno)).toUtf8());}}};home(false);DELAY(100);home(true);

3,读取double

            while (!bExit){const int read_regAddress = 1104;const int numBits = 4;uint16_t coilStatus[numBits];int rc;{QMutexLocker locker(&mutex);rc = modbus_read_registers(modbusContext,read_regAddress,numBits,coilStatus);}if (rc == -1) {LOGE(QString("getPos Failed to read Modbus coils %1").arg(modbus_strerror(errno)).toUtf8());}else {::uint64_t combined  =  static_cast<uint64_t>(coilStatus[3]) << 48 |static_cast<uint64_t>(coilStatus[2]) << 32|static_cast<uint64_t>(coilStatus[1]) << 16| coilStatus[0];double realValue;std::memcpy(&realValue, &combined, sizeof(realValue));DataManager::Instance().setCurZ(realValue*1000);}DELAY(5);}

4,写double

//位置const int write_regAddress_pos = 1150;const int numReg = 4;::uint64_t  rawPos = *reinterpret_cast<::uint64_t*>(&ptpPos);::uint16_t listPos[4]{static_cast<uint16_t>(rawPos&0xFFFF),static_cast<uint16_t>((rawPos>>16)&0xFFFF),static_cast<uint16_t>((rawPos>>32)&0xFFFF),static_cast<uint16_t>((rawPos>>48)&0xFFFF)};int rc;{QMutexLocker locker(&mutex);rc = modbus_write_registers(modbusContext, write_regAddress_pos,numReg, listPos);}if (rc == -1) {LOGE(QString("setPos Failed to write Modbus coil %1").arg(modbus_strerror(errno)).toUtf8());}

5,注意

modbus_t 并不是线程安全的,因此在使用的地方 需要加锁。亲测这个 比Qt原生的好用

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com