QT通过QModbusRtuSerialMaster读写电子秤数据实例
一、电子称常用功能:称重、清零、去皮;电子秤的通讯方式:Modbus通信、串口通信。
二、QT读写电子秤软件界面如下:
三、核心代码如下:
.pro项目文件代码:
QT += core gui serialbus serialport
.h头文件代码
#ifndef WEIGHTDATAHELPER_H
#define WEIGHTDATAHELPER_H//添加包含文件
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QModbusRtuSerialMaster>
#include <QMutex>
#include <QMutexLocker>class WeightDataHelper : public QObject
{Q_OBJECT
public:explicit WeightDataHelper(QObject *parent = nullptr);~WeightDataHelper();public slots:void OpenPort();//打开串口void ClosePort();//关闭串口void GetWeightData();//获取称重数据void ClearZeroData();//清零void SetPortName(QString strPortName);//设置端口号void GetPortNameList();//获取所有可用的串口列表void GetDeviceState();//获取设备连接状态private slots:void slotReadWeightData();//读取称重指令发送后的的返回消息void slotWriteZeroData();//读取清零指令发送后的的返回消息void slotStateChanged(QModbusDevice::State state);//连接状态改变槽函数void slotErrorOccurred(QModbusDevice::Error error);//错误发生处理槽函数signals:void sendResult(QString strResult);//发送文本消息private:QString m_PortName = "COM10";//端口号QModbusRtuSerialMaster *m_SerialMaster;//串口通信对象bool m_Connected = false;//是否打开连接QMutex m_mutex;};
#endif // WEIGHTDATAHELPER_H
.cpp详细代码如下:
#include "weightdatahelper.h"//构造函数
WeightDataHelper::WeightDataHelper(QObject *parent) : QObject(parent)
{m_SerialMaster = new QModbusRtuSerialMaster(this);//创建通信对象connect(m_SerialMaster, SIGNAL(stateChanged(QModbusDevice::State)), this, SLOT(slotStateChanged(QModbusDevice::State))); //状态改变处理connect(m_SerialMaster, SIGNAL(errorOccurred(QModbusDevice::Error)), this, SLOT(slotErrorOccurred(QModbusDevice::Error))); //发生错误处理
}//析构函数
WeightDataHelper::~WeightDataHelper()
{if (m_SerialMaster){m_SerialMaster->disconnectDevice();}delete m_SerialMaster;m_SerialMaster=nullptr;qDebug()<<"调用WeightDataHelper析构函数";
}//连接状态改变槽函数
void WeightDataHelper::slotStateChanged(QModbusDevice::State state)
{switch (state){case QModbusDevice::ConnectingState:{m_Connected = false;break;}case QModbusDevice::ConnectedState:{m_Connected = true;break;}case QModbusDevice::ClosingState:{m_Connected = false;break;}case QModbusDevice::UnconnectedState:{m_Connected = false;break;}default:break;}emit sendResult(QString("最新状态:%1").arg(m_Connected));
}//错误发生处理槽函数
void WeightDataHelper::slotErrorOccurred(QModbusDevice::Error error)
{emit sendResult("发生错误:"+m_SerialMaster->errorString());
}//设置端口号
void WeightDataHelper::SetPortName(QString strPortName)
{bool findFlag = false;foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){if(info.portName()==strPortName){findFlag = true;m_PortName = strPortName;}}if(findFlag){emit sendResult(QString("设置通信端口号为:%1成功!").arg(strPortName));}else{emit sendResult(QString("设置通信端口号为:%1失败,端口号不存在!").arg(strPortName));}
}//获取所有可用的串口列表
void WeightDataHelper::GetPortNameList()
{QString strPorName="";foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){strPorName += QString("%1;").arg(info.portName());}emit sendResult(strPorName.mid(0,strPorName.length()-1));
}//打开串口
void WeightDataHelper::OpenPort()
{if(!m_SerialMaster){return;}//设置串口相关参数m_SerialMaster->setConnectionParameter(QModbusDevice::SerialPortNameParameter,m_PortName);//设置串口信息m_SerialMaster->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,QSerialPort::Baud9600);//设置波特率m_SerialMaster->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,QSerialPort::Data8);//设置数据位m_SerialMaster->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);//设置校验m_SerialMaster->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::OneStop);//设置停止位m_SerialMaster->setTimeout(1000);//设置超时时间m_SerialMaster->setNumberOfRetries(0);//设置失败重试次数//连接到设备if (m_SerialMaster->connectDevice()){m_Connected = true;//是否打开连接emit sendResult(QString("连接到串口%1成功").arg(m_PortName));}else{m_Connected = false;//是否打开连接emit sendResult("连接失败: "+ m_SerialMaster->errorString());}
}
//关闭串口
void WeightDataHelper::ClosePort()
{if (m_SerialMaster){qDebug()<<"调用关闭串口函数";m_SerialMaster->disconnectDevice();}emit sendResult(QString("断开到串口%1的连接成功").arg(m_PortName));
}//获取设备连接状态
void WeightDataHelper::GetDeviceState()
{emit sendResult(QString("连接状态:%1 串口号:%2").arg(m_Connected).arg(m_PortName));
}//清零操作入口
void WeightDataHelper::ClearZeroData()
{if(!m_Connected){emit sendResult("请连接电子称后再操作");return;}//[2025-09-08 15:11:49-524]COM10-发送:01 06 00 26 00 01 a9 c1//[2025-09-08 15:11:49-545]COM10-接收:01 06 00 26 00 01 a9 c1QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 38, 1);// 定义数据单元:保持寄存器类型、开始地址38和读取数量1QMutexLocker locker(&m_mutex); // 创建QMutexLocker对象并传入m_mutexif (QModbusReply *writeReply = m_SerialMaster->sendWriteRequest(unit, 1)){if (!writeReply->isFinished()){
// connect(writeReply,&QModbusReply::finished,this,[this,writeReply](){
// if(writeReply->error() == QModbusDevice::NoError)
// {
// const QModbusDataUnit result = writeReply->result();
// QString strWeight;
// for (uint i = 0; i < result.valueCount(); ++i) {
// strWeight += QString::number(result.value(i)) + " "; //将数据值转换为字符串
// }
// qDebug()<<(QString("数据值:%1").arg(strWeight));
// emit sendResult(strWeight);
// }
// else
// {
// qDebug()<<(QString("系统错误:%1").arg(writeReply->errorString()));
// emit sendResult(writeReply->errorString());
// }
// });connect(writeReply, SIGNAL(finished()), this, SLOT(slotWriteZeroData())); //异步处理槽函数}else{if (writeReply->error() != QModbusDevice::NoError){emit sendResult(writeReply->errorString());delete writeReply;}}}else{emit sendResult(QString("发送请求数据失败:%1").arg(m_SerialMaster->errorString()));}
}
//读取清零指令发送后的的返回消息
void WeightDataHelper::slotWriteZeroData()
{//接收:01 03 04 00 00 01 fe 7a 23auto writeReply = qobject_cast<QModbusReply*>(sender());if (!writeReply){qDebug()<<"写寄存器返回不为空";if (writeReply->error() == QModbusDevice::NoError){const QModbusDataUnit unit = writeReply->result();//读取响应数据QVector<quint16> vecResult = unit.values();int startAddress = unit.startAddress();qDebug()<<startAddress;if(unit.valueCount() >1){emit sendResult(QString("清零操作返回的数据长度:%1 数据1:%2 数据2:%3").arg(unit.valueCount()).arg(QString::number(vecResult.at(0))).arg(QString::number(vecResult.at(1))));}else{emit sendResult(QString("清零操作返回的数据长度:%1 数据值:%2").arg(unit.valueCount()).arg(QString::number(vecResult.at(0))));}}else if (writeReply->error() == QModbusDevice::ProtocolError){emit sendResult(QString("清零操作返回数据协议出错: %1").arg(writeReply->errorString()));}else{emit sendResult(QString("清零操作返回数据出错: %1").arg(writeReply->errorString()));}writeReply->deleteLater(); // 释放内存}else{qDebug()<<"写寄存器返回为空";emit sendResult("设置清零指令时返回空");}
}
//获取称重数据
void WeightDataHelper::GetWeightData()
{if(!m_Connected){emit sendResult("请连接电子称后再操作");return;}QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 0, 2);// 定义数据单元:保持寄存器类型、PLC的开始地址和地址读取数QMutexLocker locker(&m_mutex); // 创建QMutexLocker对象并传入m_mutex,当前函数执行完成则自动的调用析构函数来解锁if(QModbusReply *readReply = m_SerialMaster->sendReadRequest(unit, 1)){qDebug()<<"请求未完成";if(!readReply->isFinished()){qDebug()<<"绑定回复完成的信号";
// connect(readReply,&QModbusReply::finished,this,[this,readReply](){
// if(readReply->error() == QModbusDevice::NoError)
// {
// const QModbusDataUnit result = readReply->result();
// QString strWeight;
// for (uint i = 0; i < result.valueCount(); ++i) {
// strWeight += QString::number(result.value(i)) + " "; //将数据值转换为字符串
// }
// qDebug()<<(QString("数据值:%1").arg(strWeight));
// emit sendResult(strWeight);
// }
// else
// {
// qDebug()<<(QString("系统错误:%1").arg(readReply->errorString()));
// emit sendResult(readReply->errorString());
// }
// });connect(readReply, SIGNAL(finished()), this, SLOT(slotReadWeightData())); //异步处理槽函数}else{qDebug()<<"请求已完成";if (readReply->error() != QModbusDevice::NoError){emit sendResult(readReply->errorString());delete readReply;}}}else{qDebug()<<"请求错误";emit sendResult(m_SerialMaster->errorString());}
}//读取称重数据槽函数
void WeightDataHelper::slotReadWeightData()
{auto readReply = qobject_cast<QModbusReply*>(sender());if (readReply){qDebug()<<"读取称重数据时返回非空";if (readReply->error() == QModbusDevice::NoError){const QModbusDataUnit unit = readReply->result();//读取响应数据QString strWeight;for (uint i = 0; i < unit.valueCount(); ++i) {strWeight += QString::number(unit.value(i)) + " "; //将数据值转换为字符串}qDebug()<<(QString("数据值:%1").arg(strWeight));emit sendResult(strWeight);}else if (readReply->error() == QModbusDevice::ProtocolError){qDebug()<<"读取称重返回数据协议出错";emit sendResult(QString("读取称重返回数据协议出错: %1").arg(readReply->errorString()));}else{qDebug()<<"读取称重返回数据出错";emit sendResult(QString("读取称重返回数据出错: %1").arg(readReply->errorString()));}readReply->deleteLater(); //通过事件循环延迟删除}else{qDebug()<<"读取称重数据时返回空";emit sendResult("读取称重数据时返回为空");}
}
四、相关问题需处理:
4.1 当前代码直接可以在QT中运行,但是封装称DLL后不能正常提供给C#调用,需要调整为同步获取返回结果。
4.2 返回的寄存器数据需要通过大小端转换显示正确的数据。
4.3 使用串口调试助手可直接发命令给到电子秤读写内部寄存器数据