Qt 开发modbus 可能遇到的问题解决

1,要解析协议,首先要弄清楚报文格式,其中modbustcp协议中的标准格式为:

MBAP报文头(7byte) + 功能码(1byte)+ 数据(n byte)

MBAP报文头包括:
        1.事务处理标识符    2字节    (表示当前的操作事务类型,例如:读取温度0x00  0x01, 读取压力0x00 0x02  )
        2.协议标识符    2字节    0=Modbus协议  
        3.长度    2字节    后续字节的数量  (单元标识符,功能码,和数据)
        4.单元标识符    1字节(表示从机编号,一个modbus主机可对应多个从机)    

2.了解报文之后,接下来需要对功能码进行认识,对于协议来说,功能码有以下几项:

        0x01 读线圈(coils)状态,读取单个或多个

        0x02 读离散输入(discreteinputs)状态,读取单个或多个

        0x03 读保持寄存器(holdingregisters),读取单个或多个

        0x04 读输入寄存器(inputregisters),读取单个或多个

        0x05 写单个线圈(coils)状态,单个写入

        0x06 写单个保持寄存器(holdingregisters),单个写入

        0x0F 写多个线圈(coils),多个写入

        0x10 写多个保持寄存器(holdingregisters),多个写入

3.了解报文之后,可以进行发送数据的组织了,下面是数据组织:

例子:写入和读取保持寄存器代码如下:

void ModbusTcpHandler::writeHoldingRegister(quint16 address, quint16 value)
{
    QByteArray request;
    request.resize(12);

    uchar addh = address/256;
    uchar addl = address%256;

    request[0]=addh;//事务处理标识符 2byte
    request[1]=addl;
    request[2]=0x00;//协议标识符 2byte
    request[3]=0x00;
    request[4]=0x00;//数据长度 2byte
    request[5]=0x06;
    request[6]=0x01;//单元标识符 1byte

    request[7]=0x06;//功能码 1byte

    request[8]=addh;//起始地址h
    request[9]=addl;//起始地址l

    uchar valueh = value/256;
    uchar valuel = value%256;
    request[10]=valueh;//值1h
    request[11]=valuel;//值1l
    m_tcpSocket->write(request);

    qDebug () << Q_FUNC_INFO << request;

}
void ModbusTcpHandler::readHoldingRegister(quint16 address, quint16 value)
{
    QByteArray request;
    request.resize(12);
    uchar addh = address/256;
    uchar addl = address%256;

    request[0]=addh;//事务处理标识符 2byte
    request[1]=addl;
    request[2]=0x00;//协议标识符 2byte
    request[3]=0x00;
    request[4]=0x00;//数据长度 2byte
    request[5]=0x06;
    request[6]=0x01;//单元标识符 1byte
    request[7]=0x03;//功能码 1byte
    request[8]=addh;//起始地址h
    request[9]=addl;//起始地址l
    uchar valueh = value/256;
    uchar valuel = value%256;

    request[10]=valueh;//读取数量值1h
    request[11]=valuel;//读取数量值1l

    qint64 nWriteData = m_tcpSocket->write(request);
    if (!m_tcpSocket->waitForBytesWritten(2000)) {
        qDebug () << Q_FUNC_INFO << m_tcpSocket->errorString();
    }

    qDebug () << Q_FUNC_INFO << nWriteData << request.toHex();
}

3.发送完数据之后,接下来就是数据处理部分:

        由于接收到的数据是char*[] 数组,对于char的处理函数有:

        4个char转浮点类型函数:

float ModbusTcpHandler::parse4Int2Float(quint8 value1, quint8 value2, quint8 value3, quint8 value4)
{
    // 合并为 32 位整数
    uint32_t combined = (static_cast<uint32_t>(value1) << 24) |
            (static_cast<uint32_t>(value2) << 16) |
            (static_cast<uint32_t>(value3) << 8)  |
            static_cast<uint32_t>(value4);

    float fData = *reinterpret_cast<float*>(&combined);

    qDebug () << Q_FUNC_INFO << combined << fData;

    return fData;
}

        还有两个char转uint16:

quint16 ModbusTcpHandler::parse2Int2Int(quint8 value1, quint8 value2)
{
    quint16 combined = (static_cast<quint16>(value1) << 8) | value2;

    quint16 nValue = static_cast<quint16>(combined);
    qDebug () << Q_FUNC_INFO << nValue;

    return nValue;
}

有了这两个函数,数据基本上就可以完成处理了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值