关于QT Modbus RTU 的总结

关于QT Modbus RTU 的总结

写在前面的话:作为一个qt小白,还在不断学习的过程中,写博客是为了记录自己遇到的问题,这是自己原创的第一篇博客,思路还比较混乱,后续还会慢慢梳理逻辑,补充和完善相关的知识点,博客中很多地方可能有各种错误的地方,欢迎各位大神指正。

一、编写流程:
1.modbus库的移植
2.头文件和配置文件
3.建立连接
4.读写报文函数(不完善,目前只用了sendWriteRequest()这个函数,读数据还在研究中)

二、modbus库的移植
关于QT Modbus RTU 的总结_第1张图片

三、头文件和配置文件
.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

关于QT Modbus RTU 的总结_第2张图片

根据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();
}

你可能感兴趣的:(qt学习,qt5,modbus,qt)