经过汇川AM403测试的Modbus Tcp 类的C++实现

1.头文件

#ifndef CMODBUSTCP_H
#define CMODBUSTCP_H

#include <QObject>
#include <QModbusTcpClient>

class QModbusClient;
class QModbusReply;

class CModbusTcp : public QObject
{
    Q_OBJECT

public:
    enum DATAFORMAT{
        INT_FORMAT = 0,
        FLOAT_FORMAT,
        STRING_FORMAT,
        BOOL_FORMAT,
        MAXDATA_FORMAT
    };
    Q_ENUM(DATAFORMAT)

public:
    explicit CModbusTcp(QObject *parent = nullptr);
    ~CModbusTcp();

    QString m_strReceived;
    QModbusClient *m_pmodbusDevice = nullptr;

private:
    bool bHexFormatEchoDisplay;     //flag whether the echo string is hex format, default is false
    bool bHexFormatDataSend;        //flag whether the data sent is hex format, default is true

    DATAFORMAT m_analysisDataFormat;

signals:
    void signalStateChanged(bool bConnected);

    void signalDataReceived(QString strDataReceived);

    //reserved for send original data
    void signalOriginalData(QModbusDataUnit responseData);

public slots:
    void onReadReady();
    void onModbusStateChanged(QModbusDevice::State state);

    void coilRead(int nStartAddress,uint16_t numbers,int ServerID);
    void coilWrite(int nStartAddress,QString strCoilToWrite,int ServerID);
    void discreteInputRead(int nStartAddress,uint16_t numbers,int ServerID);
    void inputRegisterRead(int nStartAddress,uint16_t numbers,int ServerID);
    void holdingRegsiterRead(int nStartAddress,uint16_t numbers,int ServerID, int nDataFormat);
    void holdingRegisterWrite(int nStartAddress,QString strHoldingRegisterToWrite,int ServerID, int nDataFormat);

    bool connect2Server(QString strIP = "127.0.0.1", QString strPort = "502");
    void disconnectFromServer();

private:
    QString getAnalysisReturnString(QModbusDataUnit responseData);

};

#endif // CMODBUSTCP_H

2.实现文件

#include "cmodbustcp.h"


#include <QThread>
#include <QDebug>

#define DELETE_AND_SET_NULL(pointer) if(pointer != nullptr) { delete pointer; pointer = nullptr;};
#define DELETE_AND_SET_NULL_ARRAY(pointer) if(pointer != nullptr) { delete[] pointer; pointer = nullptr;};

CModbusTcp::CModbusTcp(QObject *parent) :
    QObject(parent)
    ,bHexFormatEchoDisplay(false)
    ,bHexFormatDataSend(true)
{
    m_analysisDataFormat = INT_FORMAT;

    m_pmodbusDevice = new QModbusTcpClient(this);

    connect(m_pmodbusDevice, &QModbusClient::stateChanged,this, &CModbusTcp::onModbusStateChanged);
}

CModbusTcp::~CModbusTcp()
{
    DELETE_AND_SET_NULL(m_pmodbusDevice);
}

bool CModbusTcp::connect2Server(QString strIP, QString strPort)
{
    bool bRet= false;

    m_pmodbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, strIP);
    m_pmodbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, strPort.toInt());
    m_pmodbusDevice->setTimeout(1000);
    m_pmodbusDevice->setNumberOfRetries(3);

    bRet = m_pmodbusDevice->connectDevice();
    if(bRet)
    {
        qDebug()<< "connect to PLC OK";
    } else {
        qDebug()<< "connect to PLC Fail";
    }

    return bRet;
}

void CModbusTcp::disconnectFromServer()
{
    if(m_pmodbusDevice) m_pmodbusDevice->disconnectDevice();
}

void CModbusTcp::coilRead(int nStartAddress,uint16_t numbers,int ServerID)
{
    if(m_pmodbusDevice)
    {
        QModbusDataUnit data(QModbusDataUnit::Coils, nStartAddress, numbers);
        auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
        if(nullptr == reply)
        {
            qDebug() << "faile to send request data: " << m_pmodbusDevice->errorString();
        } else {
            if (!reply->isFinished())
            {
                connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);

            }
            else
            {
                delete reply;
            }
        }
    }
}

void CModbusTcp::coilWrite(int nStartAddress,QString strCoilToWrite,int ServerID)
{
    if(m_pmodbusDevice)
    {
        int nstrLength = strCoilToWrite.length();
        if(nstrLength == 0)
        {
            qDebug() << "Warnning:Coil String to send is Null!";
            return;
        }

        QModbusDataUnit writeData(QModbusDataUnit::Coils, nStartAddress, (nstrLength >> 1) + (nstrLength & 1));

        for (uint i = 0; i < writeData.valueCount(); i++)
        {
            writeData.setValue(i, strCoilToWrite.at(2*i).unicode() - '0');
        }

        qDebug() << "data sent is: " << writeData.values();

        QModbusReply* reply = m_pmodbusDevice->sendWriteRequest(writeData, ServerID);
        if (reply)
        {
            if (!reply->isFinished())
            {
                connect(reply, &QModbusReply::finished, this, [this, reply](){
                    if (reply->error() == QModbusDevice::ProtocolError)
                    {
                        qDebug() << "data written error: " << reply->errorString();
                    }
                    else if (reply->error() != QModbusDevice::NoError)
                    {
                        qDebug() << "data written error: " << reply->errorString();
                    }
                    else
                    {
                        const QModbusDataUnit data = reply->result();

                        qDebug() << "data written: " << data.values();

                        m_strReceived = "";
                        for(auto value: data.values())
                        {
                            m_strReceived += tr("%1 ").arg(value);
                        }

                        emit signalDataReceived(m_strReceived);

                    }

                    reply->deleteLater();
                });
            }
            else
            {
                reply->deleteLater();
            }
        }
        else
        {
            qDebug() << "sendWriteRequest Error: " << reply->errorString();
        }
    }
}

void CModbusTcp::discreteInputRead(int nStartAddress,uint16_t numbers,int ServerID)
{
    if(m_pmodbusDevice)
    {
        QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, nStartAddress, numbers);

        auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
        if (nullptr == reply)
        {
            qDebug() << "fail to send data: " << m_pmodbusDevice->errorString();
        }
        else
        {
            if (!reply->isFinished())
            {
                connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
            }
            else
            {
                delete reply;
            }
        }
    }
}

void CModbusTcp::inputRegisterRead(int nStartAddress,uint16_t numbers,int ServerID)
{
    if(m_pmodbusDevice)
    {
        QModbusDataUnit data(QModbusDataUnit::InputRegisters, nStartAddress, numbers);

        QModbusReply* reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
        if (nullptr == reply)
        {
            qDebug() << "failed to send data: " << m_pmodbusDevice->errorString();
        }
        else
        {
            qDebug() << "input register Read command have sent";

            if (!reply->isFinished())
            {
                qDebug() << "input register Read command is running";
                connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
            }
            else
            {
                qDebug() << "input register Read command immediately reply";
                delete reply;
            }
        }
    }
}

void CModbusTcp::holdingRegsiterRead(int nStartAddress,uint16_t numbers,int ServerID, int nDataFormat)
{
    assert((nDataFormat >=0) && (nDataFormat < MAXDATA_FORMAT));

    m_analysisDataFormat = DATAFORMAT(nDataFormat);

    if(m_pmodbusDevice)
    {
        QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, nStartAddress, numbers);

        auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
        if (nullptr == reply)
        {
            qDebug() << "failed to send request data: " << m_pmodbusDevice->errorString();
        }
        else
        {
            if (!reply->isFinished())
            {
                connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
            }
            else
            {
                delete reply;
            }
        }
    }
}

void CModbusTcp::holdingRegisterWrite(int nStartAddress,QString strHoldingRegisterToWrite,int ServerID, int nDataFormat)
{
    assert((nDataFormat >=0) && (nDataFormat < MAXDATA_FORMAT));

    m_analysisDataFormat = DATAFORMAT(nDataFormat);

    if(m_pmodbusDevice)
    {
        QModbusDataUnit writeData;

        if (nDataFormat == INT_FORMAT)
        {
            writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, 1);
            writeData.setValue(0,strHoldingRegisterToWrite.toUShort());

        } else if (nDataFormat == FLOAT_FORMAT) {
            writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, 2);
            float fData = strHoldingRegisterToWrite.toFloat();
            unsigned char* p = (unsigned char*)&fData;
            writeData.setValue(0, *p | *(p+1) << 8);
            writeData.setValue(1, *(p+2) | *(p+3) << 8);

        } else if (nDataFormat == STRING_FORMAT) {
            int nDataLength = (strHoldingRegisterToWrite.length() >> 1) + (strHoldingRegisterToWrite.length() & 1);
            writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, nDataLength);

            for (uint i = 0; i < writeData.valueCount(); i++) {
                char tmpChar1 = strHoldingRegisterToWrite.at(2*i).toLatin1();
                char tmpChar2 = 0;
                if(2*i + 1 <= strHoldingRegisterToWrite.length() - 1 )
                {
                    tmpChar2 = strHoldingRegisterToWrite.at(2*i + 1).toLatin1();
                }
                writeData.setValue(i, tmpChar2 <<8 | tmpChar1);
            }
        } else if (nDataFormat == BOOL_FORMAT) {
            writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, 1);
            writeData.setValue(0,strHoldingRegisterToWrite.toUInt());
        }

        QModbusReply* reply = m_pmodbusDevice->sendWriteRequest(writeData, ServerID);
        if (reply)
        {
            if (!reply->isFinished())
            {
                connect(reply, &QModbusReply::finished, this, [this, reply](){
                    if (reply->error() == QModbusDevice::ProtocolError)
                    {
                        qDebug() << "data written error: " << reply->errorString();
                    }
                    else if (reply->error() != QModbusDevice::NoError)
                    {
                        qDebug() << "data written error: " << reply->errorString();
                    }
                    else
                    {
                        const QModbusDataUnit data = reply->result();

                        //solution1: send the analysis result string
                        getAnalysisReturnString(data);
                        emit signalDataReceived(m_strReceived);

                        //soltion2: send orignal data
                        //emit signalOriginalData(data);
                    }

                    reply->deleteLater();
                });
            }
            else
            {
                reply->deleteLater();
            }
        }
        else
        {
            qDebug() << "sendWriteRequest Error: " << reply->errorString();
        }
    }
}

void CModbusTcp::onReadReady()
{
    auto reply = qobject_cast<QModbusReply*>(sender());
    if (nullptr == reply)
    {
        return;
    }

    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit responseData = reply->result();

        //方案1:发送解析过的数据
        getAnalysisReturnString(responseData);
        emit signalDataReceived(m_strReceived);

        //方案2:发送原始数据包,由界面GUI解析
        //emit signalOriginalData(responseData);

    }
    else if (reply->error() == QModbusDevice::ProtocolError)
    {
        qDebug() << "Read response Protocol error: " << reply->errorString();
    }
    else
    {
        qDebug() << "Read response Error: " << reply->errorString();
    }

    reply->deleteLater();
}

void CModbusTcp::onModbusStateChanged(QModbusDevice::State state)
{
    bool bConnected=false;
    if(state == QModbusDevice::ConnectedState)
    {
        bConnected=true;
    }
    else
    {
        bConnected=false;
    }

    emit signalStateChanged(bConnected);
}

QString CModbusTcp::getAnalysisReturnString(QModbusDataUnit responseData)
{
    quint16 highword;
    quint16 lowword;
    char tmpCharArrays[4];
    float *pFloat;
    float ftemp;

    m_strReceived = "";

    switch (m_analysisDataFormat) {
    case INT_FORMAT:
        m_strReceived += tr("%1 ").arg(responseData.values()[0]);
        break;
    case FLOAT_FORMAT:
        highword = responseData.values()[0];
        lowword = responseData.values()[1];

        tmpCharArrays[0] = highword & 0xff;
        tmpCharArrays[1] = (highword >>8) & 0xff;
        tmpCharArrays[2] = lowword & 0xff;
        tmpCharArrays[3] = (lowword >>8) & 0xff;

        pFloat = (float*)&tmpCharArrays[0];

        ftemp = *pFloat;

        m_strReceived += tr("%1 ").arg(ftemp);

        break;

    case STRING_FORMAT:
        char chTmp1;
        char chTmp2;
        for(auto value: responseData.values())
        {
            chTmp1 = value & 0xff;
            chTmp2 = (value >> 8) & 0xff;
            m_strReceived += tr("%1%2").arg(chTmp1).arg(chTmp2);
        }

        break;
    case BOOL_FORMAT:
        m_strReceived += tr("%1 ").arg(responseData.values()[0]);
        break;

    default:
        qDebug() << "NOT SUPPORTED DATA FORMAT!!!";
        break;
    }

    return m_strReceived;

}

汇川AM403PLC是一种常用的工业自动化控制设备,具备Modbus TCP通讯协议的主站功能。作为主站,AM403PLC可以与其他支持Modbus TCP协议的设备建立通讯链路,实现数据的读取和写入。 在建立通讯链路之前,首先需要配置和设置AM403PLC的网络参数,包括IP地址、子网掩码和网关等。确保与其他设备在同一个网络中。然后,在AM403PLC的编程软件中,编写相应的程序来实现Modbus TCP通讯。 具体的通讯步骤如下: 1. 创建通讯对象:在编程软件中创建一个Modbus TCP通讯对象,设置好通讯协议、IP地址和通讯端口等参数。 2. 建立连接:通过调用相应的函数或指令,将通讯对象与目标设备建立连接。这一步骤会自动进行TCP握手等通讯协议的处理,确保连接的可靠性。 3. 数据读取和写入:通过调用相应的函数或指令,实现数据的读取和写入操作。可以根据需要,读取其他设备的数据,或者将数据写入其他设备。 4. 关闭连接:通讯完成后,需要通过调用相应的函数或指令,关闭与目标设备的连接。这样可以释放资源,并确保通讯的正常结束。 需要注意的是,对于Modbus TCP通讯,需严格遵守通讯协议的规定,包括数据传输格式、寄存器地址的定义等。同时,在编写程序时,需要考虑到通讯的可靠性和实时性,以及异常情况的处理等。 总之,汇川AM403PLC作为Modbus TCP主站通讯实例,可以通过配置网络参数、建立连接、数据读写等步骤来实现与其他设备的通讯。这为工业自动化控制系统的设计和实现提供了一种可靠的通讯方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值