QT技巧系列(9)QModbusTcpClient使用Modbus Tcp客户端程序示例及代码
本文详细介绍了采用QModbusTcpClient类作为MODBUS客户端程序的主要流程和主要函数示例代码,供大家参考。
包含文件:
#include <QModbusDataUnit>
#include <QModbusTcpClient>
#include <QModbusRtuSerialMaster>
1、首先连接到服务端
构造函数中
//QModbusClient *modbusDevice;
modbusDevice = new QModbusTcpClient(this);
connect(modbusDevice, &QModbusClient::stateChanged,
this, &loraThread::onStateChanged);//连接状态发生改变时处理函数(connect or discennect)
连接函数代码:
void loraThread::connectJzq()
{
qDebug()<<"开始连接线程:"<<QThread::currentThread(); //显示当前线程的数值
if(!modbusDevice)
{
return;
}
if(modbusDevice->state() != QModbusDevice::ConnectedState)
{
const QUrl url = QUrl::fromUserInput("192.168.2.111:502"); //;//获取IP和端口号
modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
modbusDevice->setTimeout(500);
modbusDevice->setNumberOfRetries(3);
if(!modbusDevice->connectDevice())//连接失败
{
isConnected = false;
}
else//成功连接
{
isConnected = true;
}
}
else
{
isConnected = false;
modbusDevice->disconnectDevice();
//emit change2Con();
}
qDebug() << modbusDevice->state();
}
2、发送读或写请求到服务端
写请求代码:
给QModbusDataUnit赋值后发送写请求sendWriteRequest,写到相应寄存器中的相应位置,操作成功,没有发生错误的话sendWriteRequest将返回一个QModbusReply,否则返回空指针。当reply完成或放弃后reply->isFinished()将返回true。
void loraThread::on_writeTor(QString t)
{
if (!modbusDevice)
return;
QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, 4, 2);
for (uint i = 0; i < writeUnit.valueCount(); i++)
{
int ii = static_cast<int>(i);
int j = 4*ii;
QString st = t.mid (j,4);
bool ok;
int hex =st.toInt(&ok,16);//将读取到的数据转换为16进制发送
quint16 qhex =static_cast<quint16>(hex);
// qDebug()<<writeUnit.valueCount();
writeUnit.setValue(ii,qhex);
}
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, 1)) {//1->modbus 地址
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() == QModbusDevice::ProtocolError)
{
emit statusBar(tr("Write response error: %1 (Mobus exception: 0x%2)")
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16));
} else if (reply->error() != QModbusDevice::NoError)
{
emit statusBar(tr("Write response error: %1 (code: 0x%2)").
arg(reply->errorString()).arg(reply->error(), -1, 16));
}
reply->deleteLater();
});
} else {
// broadcast replies return immediately
reply->deleteLater();
}
} else {
emit statusBar(tr("Write error: ") + modbusDevice->errorString());
}
}
读请求代码:
发送sendReadRequest读请求,成功则异步函数回调处理读回的数据,错误则进行相应的处理。代码如下:
void loraThread::readDevice()
{
if(!isConnected)return;
if (!modbusDevice)
{
return;
}
qDebug()<<"read device";
QModbusDataUnit readUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, 520, 50);
if (auto *reply = modbusDevice->sendReadRequest(readUnit, 1)) //1->modbus设备地址
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &loraThread::toReadReady);
}
else
{
delete reply; // broadcast replies return immediately
}
}
else
{
//emit statusBar(tr("Read error: ") + modbusDevice->errorString());
}
QThread::msleep(1);
}
读请求成功异步回调函数处理读回的数据,参考代码如下:
void loraThread::toReadReady()
{
//QModbusReply这个类存储了来自client的数据,sender()返回发送信号的对象的指针
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
{
return;
}
if (reply->error() == QModbusDevice::NoError)
{
//处理成功返回的数据
const QModbusDataUnit unit = reply->result();
//quint16 stat = unit.value(1); //状态(位与关系)
。。。。。。
}
else if (reply->error() == QModbusDevice::ProtocolError)
{
emit statusBar(tr("Read response error: %1 (Mobus exception: 0x%2)").
arg(reply->errorString()).
arg(reply->rawResult().exceptionCode(), -1, 16));
}
else
{
emit statusBar(tr("Read response error: %1 (code: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), -1, 16));
}
reply->deleteLater();
}
状态变化处理代码:
void loraThread::onStateChanged(int state)//连接状态发生改变时处理函数(connect or discennect)
{
if (state == QModbusDevice::UnconnectedState)
{
//ui->connectButton_2->setText(tr("Connect"));
isConnected = false;
//emit updateCount("0,0");
}
else if (state == QModbusDevice::ConnectedState)
{
//ui->connectButton_2->setText(tr("Disconnect"));
isConnected = true;
}
}
注:实战示例,解疑答惑。
--不间端地思考,实时地批判你的工作!