一、电子称常用功能:称重、清零、去皮;电子秤的通讯方式: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 c1
QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 38, 1);// 定义数据单元:保持寄存器类型、开始地址38和读取数量1
QMutexLocker locker(&m_mutex); // 创建QMutexLocker对象并传入m_mutex
if (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 23
auto 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 使用串口调试助手可直接发命令给到电子秤读写内部寄存器数据