QT通过QModbusRtuSerialMaster读写电子秤数据实例

发布于:2025-09-12 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、电子称常用功能:称重、清零、去皮;电子秤的通讯方式: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  使用串口调试助手可直接发命令给到电子秤读写内部寄存器数据