写在前面的话:作为一个qt小白,还在不断学习的过程中,写博客是为了记录自己遇到的问题,这是自己原创的第一篇博客,思路还比较混乱,后续还会慢慢梳理逻辑,补充和完善相关的知识点,博客中很多地方可能有各种错误的地方,欢迎各位大神指正。
一、编写流程:
1.modbus库的移植
2.头文件和配置文件
3.建立连接
4.读写报文函数(不完善,目前只用了sendWriteRequest()这个函数,读数据还在研究中)
三、头文件和配置文件
.pro文件需要依赖:
QT += serialport
QT += serialbus
QT += core gui
win32:LIBS += -lws2_32
mainwindow.h===>
#include
#include
#include
#include
#include
#include
#include
#include
#include "modbus/modbus.h"
#include "modbus/modbus-private.h"
#include "modbus/modbus-rtu-private.h"
#include "modbus/modbus-rtu.h"
#include "modbus/modbus-version.h"
四、进行连接
void MainWindow::Modbus_RTU()//
{
if (modbusDevice) modbusDevice->disconnectDevice();
delete modbusDevice;
modbusDevice = nullptr;
modbusDevice = new QModbusRtuSerialMaster(this);
connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
statusBar()->showMessage(modbusDevice->errorString(), 5000);
});
if (!modbusDevice) {
statusBar()->showMessage(tr("Could not create Modbus master."), 5000);
return;
}
QString portname;
portname="COM1";
statusBar()->clearMessage();
if (modbusDevice->state() != QModbusDevice::ConnectedState)
{
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
portname );
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
QSerialPort::EvenParity);
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
QSerialPort::Baud4800);
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
QSerialPort::Data8);
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
QSerialPort::OneStop);
statusBar()->showMessage(tr("Connect Success "));
if (!modbusDevice->connectDevice()) {
statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
}
}
else {
modbusDevice->disconnectDevice();
}
}
步骤解析:
1、删除modbus设备对象,有的时候加这一步运行会出错。
出错原因还未找到,删掉这段好像对功能的实现没有影响。
2、创建modbus对象
//检查是否创建modbus master成功
3、配置modbus设备参数,可以按需要更改。
需要先检查modbus设备是否存在
//检查modbusDevice是否连接成功
可配合软件USR-TCP232-Test串口调试助手、Configure Virtual Serial Port Driver虚拟串口设置来测试是否连接成功。
五、写报文函数
void MainWindow::sendModbus()
{
unsigned int regStartAddr = 0;//寄存器起始地址
if (!modbusDevice)
return;
statusBar()->clearMessage();
QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, regStartAddr, 1);
unsigned int number;
number = 0x08;
writeUnit.setValue(0,number);
auto *reply = modbusDevice->sendWriteRequest(writeUnit, g_DevAllParamAddr);
if(!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if(reply->isFinished())
if (reply->error() == QModbusDevice::ProtocolError) {
statusBar()->showMessage(tr("Write response error: %1 (Mobus exception: 0x%2)")
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16),
5000);
} else if (reply->error() != QModbusDevice::NoError) {
statusBar()->showMessage(tr("Write response error: %1 (code: 0x%2)").
arg(reply->errorString()).arg(reply->error(), -1, 16), 5000);
}
reply->deleteLater();
});
}
}
利用串口调试助手收到的报文:
FE 06 00 00 00 08 9C 03
FE 06 00 00 00 08 9C 03
FE 06 00 00 00 08 9C 03
FE 06 00 00 00 08 9C 03
根据modbus协议的说明文件modbus功能码定义和样例
可以具体分析这些报文的含义,在运用到不同的项目中时,也可以自己写modbus规约文件,怎么写这个还在学习中。
读报文实例代码,在做智能双确认开关监测的时候有用到。
void MainWindow::readModbus()
{
if (!modbusDevice)
return;
statusBar()->clearMessage();
QModbusDataUnit readUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs, 0, 0x08);
auto *reply = modbusDevice->sendReadRequest(readUnit, MODBUS_DEV1_ADDR);
if(reply != NULL)
{
if(!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &MainWindow::dev1DataProc);
else
delete reply;
}
QModbusDataUnit readUnit1 = QModbusDataUnit(QModbusDataUnit::DiscreteInputs, 0, 0x08);
auto *reply1 = modbusDevice->sendReadRequest(readUnit1, MODBUS_DEV2_ADDR);
if(reply1 != NULL)
{
if(!reply1->isFinished())
connect(reply1, &QModbusReply::finished, this, &MainWindow::dev2DataProc);
else
delete reply1;
}
}
void MainWindow::dev1DataProc()
{
bool tempZtFen = false;
bool tempZtHe = false;
bool tempWdFen = false;
bool tempWdHe = false;
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit readUnit_reply = reply->result();
tempZtFen = readUnit_reply.value(0);
tempZtHe = readUnit_reply.value(1);
if(tempZtFen && !tempZtHe)
{
g_ztAState = false;
g_ztBState = false;
g_ztCState = false;
}
else if(tempZtHe && !tempZtFen)
{
g_ztAState = true;
g_ztBState = true;
g_ztCState = true;
}
tempWdFen = readUnit_reply.value(2);
tempWdHe = readUnit_reply.value(3);
if(tempWdFen && !tempWdHe)
g_wdAState = false;
else if(!tempWdFen && tempWdHe)
g_wdAState = true;
tempWdFen = readUnit_reply.value(4);
tempWdHe = readUnit_reply.value(5);
if(tempWdFen && !tempWdHe)
g_wdBState = false;
else if(!tempWdFen && tempWdHe)
g_wdBState = true;
tempWdFen = readUnit_reply.value(6);
tempWdHe = readUnit_reply.value(7);
if(tempWdFen && !tempWdHe)
g_wdCState = false;
else if(!tempWdFen && tempWdHe)
g_wdCState = true;
g_wdPortAState = readUnit_reply.value(3);
g_wdPortBState = readUnit_reply.value(4);
g_wdPortCState = readUnit_reply.value(5);
g_wdHelpState = readUnit_reply.value(6);
g_ztHelpState = readUnit_reply.value(6);
if(g_wdAState && g_wdBState && g_wdCState && \
g_wdPortAState && g_wdPortBState && g_wdPortCState && \
g_wdHelpState)
g_wdTotalState = true;
else
g_wdTotalState = false;
}
reply->deleteLater();
}
void MainWindow::dev2DataProc()
{
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit readUnit_reply1 = reply->result();
g_ztPortAState = readUnit_reply1.value(0);
g_ztPortBState = readUnit_reply1.value(1);
g_ztPortCState = readUnit_reply1.value(2);
if(g_wdAState && g_wdBState && g_wdCState && \
g_ztPortAState && g_ztPortBState && g_ztPortCState && \
g_wdHelpState)
g_ztTotalState = true;
else
g_ztTotalState = false;
}
reply->deleteLater();
}