Qt 通过 Qt Serial Bus 模块提供 Modbus RTU 支持,需在 Qt 安装时勾选该模块。在项目配置文件(.pro)中添加依赖:
QT += core gui serialbus serialport
CONFIG += c++17
确保串口设备(如 USB 转 RS485 适配器)已正确连接,并在代码中指定对应端口(如 COM3 或 /dev/ttyUSB0)或者使用Modbus仿真软件进行模拟测试。
m_modbusRtuDevice = new QModbusRtuSerialMaster(this);
connect(m_modbusRtuDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
ui->textEdit->append(m_modbusRtuDevice->errorString());
});
connect(m_modbusRtuDevice,&QModbusClient::stateChanged,[this](QModbusDevice::State state){
if(state==QModbusDevice::UnconnectedState){
ui->textEdit->append("connect ModbusTcp Device failed");
}
else if(state==QModbusDevice::ConnectedState){
ui->textEdit->append("connect ModbusTcp Device success!");
}
else if(state==QModbusDevice::ClosingState){
ui->textEdit->append("connect ModbusTcp Device Closing.");
}
});
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
m_comName);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
m_parity);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
m_baud);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
m_dataBits);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
m_stopBits);
m_modbusRtuDevice->setTimeout(1000);
m_modbusRtuDevice->setNumberOfRetries(3);
m_modbusRtuDevice->connectDevice();
此代码配置了串口参数并尝试连接设备,需根据硬件实际情况调整波特率、端口号等。
读取保持寄存器(功能码 0x03):
QString sendFrame = QString("%1%2%3%4").arg(slaveId,2,16,QLatin1Char('0'))
.arg(fcode,2,16,QLatin1Char('0'))
.arg(startAddress,4,16,QLatin1Char('0'))
.arg(readNum,4,16,QLatin1Char('0'));
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(sendFrame.toUtf8())),4,16,QLatin1Char('0'));
sendFrame = QString("%1%2").arg(sendFrame,crc16);
ui->textEdit->append(QString("发送:%1").arg(QString::fromUtf8(QByteArray::fromHex(sendFrame.toUtf8()).toHex(' ').toUpper())));
QModbusDataUnit read;
switch (fcode) {
case 0x01:
read = QModbusDataUnit(QModbusDataUnit::Coils, startAddress, readNum);//读线圈
break;
case 0x02:
read = QModbusDataUnit(QModbusDataUnit::DiscreteInputs, startAddress, readNum);//读离散量输入
break;
case 0x03:
read = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, readNum);//读保持寄存器
break;
case 0x04:
read = QModbusDataUnit(QModbusDataUnit::InputRegisters, startAddress, readNum);//读输入寄存器
break;
default:
ui->textEdit->append("read frame error.");
return;
break;
}
if (auto *reply = m_modbusRtuDevice->sendReadRequest(read, slaveId)) {
if (!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &MainWindow::onReadModbus);
else{
delete reply;
connectModbus();
}
}
else{
ui->textEdit->append("Read error: "+m_modbusRtuDevice->errorString());
connectModbus();
}
写入单个线圈(功能码 0x06):
if (!m_modbusRtuDevice)
connectModbus();
else if (m_modbusRtuDevice->state() != QModbusDevice::ConnectedState)
connectModbus();
QString sendFrame = QString("%1%2%3").arg(slaveId,2,16,QLatin1Char('0'))
.arg(0x06,2,16,QLatin1Char('0'))
.arg(startAddress,4,16,QLatin1Char('0'));
QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAddress, values.size());
for(int i=0; i<values.size(); i++){
writeUnit.setValue(i, values.at(i));
sendFrame = QString("%1%2").arg(sendFrame).arg(values.at(i),4,16,QLatin1Char('0'));
}
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(sendFrame.toUtf8())),4,16,QLatin1Char('0'));
sendFrame = QString("%1%2").arg(sendFrame,crc16);
ui->textEdit->append(QString("发送:%1").arg(QString::fromUtf8(QByteArray::fromHex(sendFrame.toUtf8()).toHex(' ').toUpper())));
QModbusReply *reply = m_modbusRtuDevice->sendWriteRequest(writeUnit,slaveId);
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() == QModbusDevice::ProtocolError)
ui->textEdit->append(QString("Write response error: %1 (Mobus exception: 0x%2)")
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16));
else if (reply->error() != QModbusDevice::NoError)
ui->textEdit->append(QString("Write response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16));
else if(reply->error() == QModbusDevice::TimeoutError)
ui->textEdit->append(QString("Write response error: %1 (code: 0x%2)")
.arg(reply->errorString()).arg(reply->error(), -1, 16));
else{
const QModbusDataUnit unit = reply->result();
m_slaverAddr = reply->serverAddress();
QVector<quint16> rValue = unit.values();
int start = unit.startAddress();
int fcode = 0x00;
if(unit.registerType() == QModbusDataUnit::HoldingRegisters)
fcode = 0x06;
else if(unit.registerType() == QModbusDataUnit::Coils)
fcode = 0x05;
QString reciveFrame;
reciveFrame=QString("%1").arg(m_slaverAddr,2,16,QLatin1Char('0'));
reciveFrame=QString("%1%2").arg(reciveFrame).arg(fcode,2,16,QLatin1Char('0'));
reciveFrame=QString("%1%2").arg(reciveFrame).arg(start,4,16,QLatin1Char('0'));
QString msg;
foreach (quint16 value, rValue){
reciveFrame=QString("%1%2").arg(reciveFrame).arg(value,4,16,QLatin1Char('0'));
msg+=QString("地址%1=%2 ").arg(start++).arg(value);
}
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(reciveFrame.toUtf8())),4,16,QLatin1Char('0'));
reciveFrame +=crc16;
ui->textEdit->append(QString("接收:%1").arg(QString::fromUtf8(QByteArray::fromHex(reciveFrame.toUtf8()).toHex(' ').toUpper())));
ui->textEdit->append("写值成功,\n"+msg);
}
reply->deleteLater();
});
}
else
reply->deleteLater();
} else{
ui->textEdit->append(QString("Write error:") + m_modbusRtuDevice->errorString());
}
多线程通信:将 Modbus 操作封装到独立线程,避免界面卡顿。
动态数据绑定:通过信号槽机制实现界面控件与 Modbus 数据的实时同步。
协议扩展:支持 Modbus TCP 混合模式(需结合 QModbusTcpClient)。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
static const quint16 crcTable[] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void InitMoubusRtu();
void connectModbus();
//写入寄存器 slaveId 写入的从机ID startAddress写入的起始地址 values写入的值
void writeUnit(int slaveId, int startAddress, QList<quint16> values);
//读取寄存器 slaveId 读取的从机ID startAddress读取的起始地址 readNum读取的数量
void readUnit(int slaveId, int fcode,int startAddress, int readNum);
quint16 crc16Modbus(const QByteArray &data);
public slots:
void onReadModbus();//读取modbus寄存器值
void disConnectModbus();
private:
Ui::MainWindow *ui;
QModbusClient *m_modbusRtuDevice = nullptr;
QString m_comName;
int m_slaverAddr;
int m_parity;
int m_baud;
int m_dataBits;
int m_stopBits;
QTimer m_timer;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList listSerial;
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
QSerialPort serial;
serial.setPort(info);
listSerial.append(serial.portName());
}
ui->numBox->addItems(listSerial);
connect(ui->openButton,&QPushButton::clicked,this,[=](){
InitMoubusRtu();
connectModbus();
});
connect(ui->sendButton,&QPushButton::clicked,this,[=](){
readUnit(ui->slaveAddrEdit->text().toInt(),ui->fcodeComBox->currentText().toInt(),ui->startEdit->text().toInt(),ui->numEdit->text().toInt());
});
connect(ui->writeButton,&QPushButton::clicked,this,[=](){
QList<quint16> values;
values.push_back(ui->writeEdit->text().toUInt());
writeUnit(ui->slaveAddrEdit->text().toInt(),ui->startEdit->text().toInt(),values);
});
connect(ui->dscBox,&QCheckBox::clicked,this,[=](){
if(ui->dscBox->checkState()==Qt::Checked){
m_timer.start(ui->tmEdit->text().toUInt());
ui->tmEdit->setDisabled(true);
}
else{
m_timer.stop();
ui->tmEdit->setEnabled(true);
}
});
connect(&m_timer,&QTimer::timeout,this,[=](){
emit ui->sendButton->clicked();
});
connect(ui->clearButton,&QPushButton::clicked,this,[=](){
ui->textEdit->clear();
});
}
MainWindow::~MainWindow()
{
disConnectModbus();
delete ui;
}
void MainWindow::InitMoubusRtu()
{
m_comName = ui->numBox->currentText();
m_baud = ui->btlBox->currentText().toInt();
m_stopBits = ui->stopBox->currentText().toInt();
m_dataBits = ui->sjwBox->currentText().toInt();
switch (ui->jywBox->currentIndex()) {
case 0:
m_parity = QSerialPort::NoParity;
break;
case 1:
m_parity = QSerialPort::EvenParity;
break;
case 2:
m_parity = QSerialPort::OddParity;
break;
default:
break;
}
m_slaverAddr = ui->slaveAddrEdit->text().toInt();
}
void MainWindow::connectModbus()
{
disConnectModbus();
m_modbusRtuDevice = new QModbusRtuSerialMaster(this);
connect(m_modbusRtuDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
ui->textEdit->append(m_modbusRtuDevice->errorString());
});
connect(m_modbusRtuDevice,&QModbusClient::stateChanged,[this](QModbusDevice::State state){
if(state==QModbusDevice::UnconnectedState){
ui->textEdit->append("connect ModbusTcp Device failed");
}
else if(state==QModbusDevice::ConnectedState){
ui->textEdit->append("connect ModbusTcp Device success!");
}
else if(state==QModbusDevice::ClosingState){
ui->textEdit->append("connect ModbusTcp Device Closing.");
}
});
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
m_comName);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
m_parity);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
m_baud);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
m_dataBits);
m_modbusRtuDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
m_stopBits);
m_modbusRtuDevice->setTimeout(1000);
m_modbusRtuDevice->setNumberOfRetries(3);
m_modbusRtuDevice->connectDevice();
}
void MainWindow::writeUnit(int slaveId, int startAddress, QList<quint16> values)
{
if (!m_modbusRtuDevice)
connectModbus();
else if (m_modbusRtuDevice->state() != QModbusDevice::ConnectedState)
connectModbus();
QString sendFrame = QString("%1%2%3").arg(slaveId,2,16,QLatin1Char('0'))
.arg(0x06,2,16,QLatin1Char('0'))
.arg(startAddress,4,16,QLatin1Char('0'));
QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAddress, values.size());
for(int i=0; i<values.size(); i++){
writeUnit.setValue(i, values.at(i));
sendFrame = QString("%1%2").arg(sendFrame).arg(values.at(i),4,16,QLatin1Char('0'));
}
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(sendFrame.toUtf8())),4,16,QLatin1Char('0'));
sendFrame = QString("%1%2").arg(sendFrame,crc16);
ui->textEdit->append(QString("发送:%1").arg(QString::fromUtf8(QByteArray::fromHex(sendFrame.toUtf8()).toHex(' ').toUpper())));
QModbusReply *reply = m_modbusRtuDevice->sendWriteRequest(writeUnit,slaveId);
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() == QModbusDevice::ProtocolError)
ui->textEdit->append(QString("Write response error: %1 (Mobus exception: 0x%2)")
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16));
else if (reply->error() != QModbusDevice::NoError)
ui->textEdit->append(QString("Write response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16));
else if(reply->error() == QModbusDevice::TimeoutError)
ui->textEdit->append(QString("Write response error: %1 (code: 0x%2)")
.arg(reply->errorString()).arg(reply->error(), -1, 16));
else{
const QModbusDataUnit unit = reply->result();
m_slaverAddr = reply->serverAddress();
QVector<quint16> rValue = unit.values();
int start = unit.startAddress();
int fcode = 0x00;
if(unit.registerType() == QModbusDataUnit::HoldingRegisters)
fcode = 0x06;
else if(unit.registerType() == QModbusDataUnit::Coils)
fcode = 0x05;
QString reciveFrame;
reciveFrame=QString("%1").arg(m_slaverAddr,2,16,QLatin1Char('0'));
reciveFrame=QString("%1%2").arg(reciveFrame).arg(fcode,2,16,QLatin1Char('0'));
reciveFrame=QString("%1%2").arg(reciveFrame).arg(start,4,16,QLatin1Char('0'));
QString msg;
foreach (quint16 value, rValue){
reciveFrame=QString("%1%2").arg(reciveFrame).arg(value,4,16,QLatin1Char('0'));
msg+=QString("地址%1=%2 ").arg(start++).arg(value);
}
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(reciveFrame.toUtf8())),4,16,QLatin1Char('0'));
reciveFrame +=crc16;
ui->textEdit->append(QString("接收:%1").arg(QString::fromUtf8(QByteArray::fromHex(reciveFrame.toUtf8()).toHex(' ').toUpper())));
ui->textEdit->append("写值成功,\n"+msg);
}
reply->deleteLater();
});
}
else
reply->deleteLater();
} else{
ui->textEdit->append(QString("Write error:") + m_modbusRtuDevice->errorString());
}
}
void MainWindow::readUnit(int slaveId, int fcode, int startAddress, int readNum)
{
//数据帧结构:地址码|功能码|起始寄存器地址+寄存器数量
QString sendFrame = QString("%1%2%3%4").arg(slaveId,2,16,QLatin1Char('0'))
.arg(fcode,2,16,QLatin1Char('0'))
.arg(startAddress,4,16,QLatin1Char('0'))
.arg(readNum,4,16,QLatin1Char('0'));
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(sendFrame.toUtf8())),4,16,QLatin1Char('0'));
sendFrame = QString("%1%2").arg(sendFrame,crc16);
ui->textEdit->append(QString("发送:%1").arg(QString::fromUtf8(QByteArray::fromHex(sendFrame.toUtf8()).toHex(' ').toUpper())));
QModbusDataUnit read;
switch (fcode) {
case 0x01:
read = QModbusDataUnit(QModbusDataUnit::Coils, startAddress, readNum);//读线圈
break;
case 0x02:
read = QModbusDataUnit(QModbusDataUnit::DiscreteInputs, startAddress, readNum);//读离散量输入
break;
case 0x03:
read = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, readNum);//读保持寄存器
break;
case 0x04:
read = QModbusDataUnit(QModbusDataUnit::InputRegisters, startAddress, readNum);//读输入寄存器
break;
default:
ui->textEdit->append("read frame error.");
return;
break;
}
if (auto *reply = m_modbusRtuDevice->sendReadRequest(read, slaveId)) {
if (!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &MainWindow::onReadModbus);
else{
delete reply;
connectModbus();
}
}
else{
ui->textEdit->append("Read error: "+m_modbusRtuDevice->errorString());
connectModbus();
}
}
void MainWindow::onReadModbus()
{
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
m_slaverAddr = reply->serverAddress();
QVector<quint16> rValue = unit.values();
int start = unit.startAddress();
int fcode = 0x00;
if(unit.registerType() == QModbusDataUnit::HoldingRegisters)
fcode = 0x03;
else if(unit.registerType() == QModbusDataUnit::Coils)
fcode = 0x01;
else if(unit.registerType() == QModbusDataUnit::DiscreteInputs)
fcode = 0x02;
else if(unit.registerType() == QModbusDataUnit::InputRegisters)
fcode = 0x04;
QString reciveFrame;
reciveFrame=QString("%1").arg(m_slaverAddr,2,16,QLatin1Char('0'));
reciveFrame=QString("%1%2").arg(reciveFrame).arg(fcode,2,16,QLatin1Char('0'));
reciveFrame=QString("%1%2").arg(reciveFrame).arg(rValue.size()*2,2,16,QLatin1Char('0'));
QString msg;
foreach (quint16 value, rValue){
reciveFrame=QString("%1%2").arg(reciveFrame).arg(value,4,16,QLatin1Char('0'));
msg+=QString("地址%1=%2 ").arg(start++).arg(value);
}
QString crc16 = QString("%1").arg(crc16Modbus(QByteArray::fromHex(reciveFrame.toUtf8())),4,16,QLatin1Char('0'));
reciveFrame +=crc16;
ui->textEdit->append(QString("接收:%1").arg(QString::fromUtf8(QByteArray::fromHex(reciveFrame.toUtf8()).toHex(' ').toUpper())));
ui->textEdit->append(msg);
}
else if (reply->error() == QModbusDevice::ProtocolError) {
ui->textEdit->append(QString("Read response error: %1 (Mobus exception: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), 2, 16,QLatin1Char('0')));
}
else {
ui->textEdit->append(QString("Read response error: %1 (code: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), 2, 16,QLatin1Char('0')));
}
reply->deleteLater();
}
void MainWindow::disConnectModbus()
{
if (!m_modbusRtuDevice)
return;
m_modbusRtuDevice->disconnectDevice();
delete m_modbusRtuDevice;
m_modbusRtuDevice = nullptr;
ui->textEdit->append("ModbusRtu断开连接");
}
quint16 MainWindow::crc16Modbus(const QByteArray &data)
{
quint16 crc = 0xFFFF;
for (auto byte : data)
crc = (crc >> 8) ^ crcTable[(crc ^ static_cast<quint8>(byte)) & 0xFF];
return ((crc & 0x00FF) << 8) | ((crc & 0xFF00) >> 8);//高低位互换
}
#include "mainwindow.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
使用Qt开发Modbus主站软件,需深入理解协议规范与Qt框架的通信机制。通过合理设计异步处理、数据展示及异常恢复策略,可构建高效稳定的工业级工具。开发者可参考开源项目进一步优化功能,适应多样化场景需求。
更多Qt开发实战持续更新中。