QT Modbus 232通信笔记。

这篇博客详细介绍了如何使用QT5.14.1及以上版本的QModbus库进行MODBUS通信。首先,设置了串口的相关参数,包括波特率、数据位、停止位和校验方式。接着,展示了写多个寄存器和读取寄存器的函数实现,包括数据转换和错误处理。最后,操作完成后关闭串口。整个过程涉及到MODBUS通信协议的CRC校验和异常处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QT版本使用≥5.14.1,之前版本通信有BUG。

协议格式:

发送报文:01 10 A0 81 00 03 06 31 00 32 00 33 00 AC C6

01:从机地址。

10:功能码。

A0 81:起始寄存器地址。

00 03:寄存器数量。

06:数据字节长度。

31 00 32 00 33 00:数据内容 123

AC C6:CRC校验低位在左高位在右。

应答报文:01 10 A0 81 00 03 F2 20

01:从机地址。

10:功能码。

A0 81:起始寄存器地址。

00 03:寄存器数量。

F2 20:CRC校验低位在左高位在右。

大概示例:

	QModbusClient  *m_modbusClient = nullptr;
	QModbusReply *m_readModbusReply;
	QModbusReply *m_sendModbusReply;

	m_modbusClient = new QModbusRtuSerialMaster;
	  

	//----------------------设置串口相关参数
	m_modbusClient->setConnectionParameter(QModbusDevice::SerialPortNameParameter,port);
	m_modbusClient->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,baudRate.toInt());
	m_modbusClient->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,QSerialPort::DataBits(dataBit.toInt()));
	m_modbusClient->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::StopBits(stopBit.toInt()));

	if(checkBit == tr("无")){
		m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::NoParity);
	}else if(checkBit == tr("奇校验")){
		m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::OddParity);
	}else{
		m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::EvenParity);
	}

	//超时时间
	m_modbusClient->setTimeout(timeout.toInt() * 1000);

	//失败重试次数
	m_modbusClient->setNumberOfRetries(0);

	if(!m_modbusClient->connectDevice())
	{
		MyToast::showTip(tr("开启端口失败"),this);
		return ;
	}

//---------------写多个寄存器
writeModbusHoldingregisters(QString data, int star_add, int number, bool isHighLowConversion)
{
    qDebug()<<"数据内容>>>"<<data;
    qDebug()<<"寄存器起始地址>>>"<<star_add;
    qDebug()<<"寄存器个数>>>"<<number;
	
	
	if (!m_modbusClient)
		return;

	if (m_modbusClient->state() != QModbusDevice::ConnectedState){
		MyToast::showTip("端口未开启",this);
		return;
	}  

    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters,star_add,number);

    if(data.length() > 0){
        for(int i = 0;i < data.length(); i++){
            //转换数据,高低位调换
            if(isHighLowConversion){
                writeUnit.setValue(i,MyUtils::highAndLowConversion_16(data.utf16()[i]));//((data & 0x00ff) << 8) | (data >> 8)
            }else{
                writeUnit.setValue(i,data.utf16()[i]);
            }
        }
    }

    QModbusReply* reply = m_modbusClient->sendWriteRequest(writeUnit, 1);

    if (reply) {

        if (!reply->isFinished()) {
            //接收响应信息
            connect(reply, &QModbusReply::finished, this, [this,reply](){
                if (reply->error() == QModbusDevice::ProtocolError)
                {
                    ui->modbus_read_plain_text_edit->appendPlainText(QString("%1 Read:%2[%3]").arg(MyUtils::getCurrentTime("yyyy-MM-dd hh:mm:ss:zzz"))
                                                                     .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 10));

                    qDebug()<<"ProtocolError>>>"<<reply->errorString();
                }
                else if (reply->error() != QModbusDevice::NoError)
                {

                    qDebug()<<"NoError>>>"<<reply->errorString();
                    ui->modbus_read_plain_text_edit->appendPlainText(QString("%1 Read:%2[%3]").arg(MyUtils::getCurrentTime("yyyy-MM-dd hh:mm:ss:zzz"))
                                                                     .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 10));
                }
                else
                {
                    //接收到的消息
                    const QModbusDataUnit data = reply->result();

                    getModbusDataUnitData(data," Read:",0x10);
                    m_data1To8SendNumber+=1;

                }

                m_modbusWriteEnd = true;
                reply->deleteLater();

            });
        } else {
            reply->deleteLater();
        }
    } else {
         ui->modbus_read_plain_text_edit->appendPlainText(QString("%1 Read:%2").arg(MyUtils::getCurrentTime("yyyy-MM-dd hh:mm:ss:zzz"))
                                                          .arg(m_modbusClient->errorString()));
        reply->deleteLater();
    }
}

//---------------读寄存器
readModbusHoldingregisters(int start_add, quint16 numbers)
{
	if (!m_modbusClient)
		return;

	if (m_modbusClient->state() != QModbusDevice::ConnectedState){
		MyToast::showTip("端口未开启",this);
		return;
	}  
	
    QModbusDataUnit ReadUnit(QModbusDataUnit::HoldingRegisters,start_add,numbers);

    if (m_sendModbusReply = m_modbusClient->sendReadRequest(ReadUnit, 1))
    {
        if (!m_sendModbusReply->isFinished())
        {
            QObject::connect(m_sendModbusReply, &QModbusReply::finished,this,&MainWindow::modbusReadReady);
        }
        else
        {
            delete m_sendModbusReply;
        }
    }else{

    }
}

//-------------读寄存器方法
modbusReadReady()
{
    m_readModbusReply = qobject_cast<QModbusReply *>(sender());

    if (!m_readModbusReply)
        return;

    if (m_readModbusReply->error() == QModbusDevice::NoError) {

        const QModbusDataUnit data = m_readModbusReply->result();
    } else if (m_readModbusReply->error() == QModbusDevice::ProtocolError) {

        ui->modbus_read_plain_text_edit->appendPlainText(QString("%1 Read:%2[%3]").arg(MyUtils::getCurrentTime("yyyy-MM-dd hh:mm:ss:zzz"))
                                                         .arg(m_readModbusReply->errorString()).arg(m_readModbusReply->rawResult().exceptionCode(), -1, 10));

    } else {
        ui->modbus_read_plain_text_edit->appendPlainText(QString("%1 Read:%2[%3]").arg(MyUtils::getCurrentTime("yyyy-MM-dd hh:mm:ss:zzz"))
                                                         .arg(m_readModbusReply->errorString()).arg(m_readModbusReply->rawResult().exceptionCode(), -1, 10));
    }
    m_readModbusReply->deleteLater();
}

//-------------------操作完毕后关闭串口
m_modbusClient->disconnectDevice();

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值