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();