一、電子稱常用功能:稱重、清零、去皮;電子秤的通訊方式: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? 使用串口調試助手可直接發命令給到電子秤讀寫內部寄存器數據