国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Qt Modbus通信】QModbus實(shí)現(xiàn)modbus的主機(jī)功能 源碼分享

這篇具有很好參考價(jià)值的文章主要介紹了【Qt Modbus通信】QModbus實(shí)現(xiàn)modbus的主機(jī)功能 源碼分享。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

modbus在上下位機(jī)數(shù)據(jù)交互時(shí)被廣泛使用,因此寫了這篇筆記和大家一起學(xué)習(xí)。
【Qt Modbus通信】libmodbus實(shí)現(xiàn)modbus的主機(jī)功能/從機(jī)功能 源碼分享
之前使用libmodbus實(shí)現(xiàn)了modbus的主從功能,但發(fā)現(xiàn)主機(jī)查詢從機(jī)的從機(jī)ID不能大于200+,因此參考QT5的modbusDEMO重新寫了一份基于QModbus實(shí)現(xiàn)的modbus主機(jī)功能。

參考文獻(xiàn)

qmodbus,QT開發(fā)筆記,qt,ui,開發(fā)語言

程序執(zhí)行效果

QT官方DEMO
qmodbus,QT開發(fā)筆記,qt,ui,開發(fā)語言modbus主機(jī) 運(yùn)行效果qmodbus,QT開發(fā)筆記,qt,ui,開發(fā)語言

源碼下載

https://gitee.com/jiang_bin_yu/QSerialBus-modbus-master/tree/master/

程序源碼

下面我將官方DEMO中的關(guān)鍵代碼移植出來,實(shí)現(xiàn)了modbus主機(jī)程序
一、項(xiàng)目配置
QT += core gui serialport serialbus
二、尋找可用串口

void MainWindow::freshSerialPortCombox()
{
    foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        QSerialPort tempSer;
        tempSer.setPort(info);
        if(tempSer.open(QIODevice::ReadWrite))
        {
            ui->comboBox_serialName->addItem(tempSer.portName());
            tempSer.close();
        }
    }
}

三、初始modbus

void MainWindow::MainWindow::InitModbus()
{
    //獲取modbus raw 數(shù)據(jù)幀
    connect(SaveLog::Instance(),&SaveLog::sigModbusData,this,&MainWindow::onModbusRawData);
    if (modbusDevice) {
        modbusDevice->disconnectDevice();
        delete modbusDevice;
        modbusDevice = nullptr;
    }

    modbusDevice = new QModbusRtuSerialMaster(this);
    connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
        qDebug() << "modbus Error:" << modbusDevice->errorString();
    });
}

四、串口連接

void MainWindow::connectModbus()
{
    disconnnectModbus();
    if (!modbusDevice)
        return;
    modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,ui->comboBox_serialName->currentText());
    modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,parity);
    modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,baud);
    modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,dataBit);
    modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,stopBit);

    modbusDevice->setTimeout(1000);
    modbusDevice->setNumberOfRetries(0);
    //連接失敗
    if(modbusDevice->connectDevice())
    {
        ui->pushButton_connect->setText("斷開連接");
        qDebug() << "連接成功";
    }
    else
    {
        ui->pushButton_connect->setText("建立連接");
        qDebug() << "連接失敗";
        QMessageBox::information(NULL,  "Title",  "串口打開失敗");
    }
}

五、寫入寄存器
a.writeUnit:寫入寄存器 slaveId 寫入的從機(jī)ID startAddress寫入的起始地址 values寫入的值

void MainWindow::writeUnit(int slaveId, int startAddress, QList<quint16> values)
{
    if (!modbusDevice)
    {
        QMessageBox::information(NULL,  "Title",  "請先連接設(shè)備");
        return;
    }
    connectModbus();
    QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAddress, values.size());
    for(int i=0; i<values.size(); i++)
    {
        writeUnit.setValue(i, values.at(i));
    }

    //serverEdit 發(fā)生給slave的ID
    if (auto *reply = modbusDevice->sendWriteRequest(writeUnit,slaveId)) {
        if (!reply->isFinished()) {
            connect(reply, &QModbusReply::finished, this, [this, reply]() {
                if (reply->error() == QModbusDevice::ProtocolError) {
                    qDebug() << QString("Write response error: %1 (Mobus exception: 0x%2)")
                                .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16);
                } else if (reply->error() != QModbusDevice::NoError) {
                    qDebug() << QString("Write response error: %1 (code: 0x%2)").
                                arg(reply->errorString()).arg(reply->error(), -1, 16);
                }
                reply->deleteLater();
            });
        } else {
            reply->deleteLater();
        }
    } else {
        qDebug() << QString(("Write error: ") + modbusDevice->errorString());
    }
}

b.writeUnit的調(diào)用方法

void MainWindow::on_pushButton_send_clicked()
{
    QList<quint16> values;
    for(quint16 i=0; i<READNUM; i++)
    {
        values.append(i);
    }
    writeUnit(0x01,0,values);	//修改從機(jī)0x01,0~50寄存器的值
}

五、讀取寄存器
a.readUnit:讀取寄存器 slaveId 讀取的從機(jī)ID startAddress讀取的起始地址 readNum讀取的數(shù)量

void MainWindow::readUnit(int slaveId, int startAddress, int readNum)
{
    if (!modbusDevice)
    {
        QMessageBox::information(NULL,  "Title",  "請先連接設(shè)備");
        return;
    }
    connectModbus();
    QMutexLocker lock(&m_modbusMutex);
    if (auto *reply = modbusDevice->sendReadRequest(QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, readNum), slaveId)) {
        if (!reply->isFinished())
            connect(reply, &QModbusReply::finished, this, &MainWindow::onReadReady);
        else
            delete reply;
    } else {
        qDebug() << "Read error: " << modbusDevice->errorString();
    }
}

b.接受modbus返回?cái)?shù)據(jù)

void MainWindow::onReadReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;

    if (reply->error() == QModbusDevice::NoError) {
        const QModbusDataUnit unit = reply->result();
        if(unit.valueCount() == READNUM)
                for (uint i = 0; i < unit.valueCount(); i++) {
                const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
                        .arg(QString::number(unit.value(i),
                                             unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));
                ui->textBrowser->append(entry);
            }
    } else if (reply->error() == QModbusDevice::ProtocolError) {
        qDebug() << QString("Read response error: %1 (Mobus exception: 0x%2)").
                    arg(reply->errorString()).
                    arg(reply->rawResult().exceptionCode(), -1, 16);
    } else {
        qDebug() << QString("Read response error: %1 (code: 0x%2)").
                    arg(reply->errorString()).
                    arg(reply->error(), -1, 16);
    }
    reply->deleteLater();
}

六、如果你想獲得你發(fā)送和接受的modbus數(shù)據(jù)幀,可以參考下我下面這個(gè)愚蠢的辦法
a.設(shè)置日志過濾器,開啟關(guān)于qt.modbus*的日志打印

    QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));

開啟后你的調(diào)試欄講會打印modbus相關(guān)的內(nèi)容qmodbus,QT開發(fā)筆記,qt,ui,開發(fā)語言
b.如果你想獲取這些內(nèi)容并發(fā)送給你的界面,你需要開啟日志重定向,即裝載新的日志鉤子(詳細(xì)請參考上面碼云提供的源碼 代碼在:QModbusDemo/savelog.cpp)

//日志重定向
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
void Log(QtMsgType type, const char *msg)
#else
void Log(QtMsgType type, const QMessageLogContext &, const QString &msg)
#endif
{
    //加鎖,防止多線程中qdebug太頻繁導(dǎo)致崩潰
    static QMutex mutex;
    QMutexLocker locker(&mutex);
    QString content;

    //這里可以根據(jù)不同的類型加上不同的頭部用于區(qū)分
    switch (type) {
    case QtDebugMsg:
        content = QString("%1").arg(msg);
        break;

    case QtWarningMsg:
        content = QString("QtWarningMsg: %1").arg(msg);
        break;

    case QtCriticalMsg:
        content = QString("QtCriticalMsg: %1").arg(msg);
        break;

    case QtFatalMsg:
        content = QString("QtFatalMsg: %1").arg(msg);
        break;
    default: break;
    }

    SaveLog::Instance()->save(content);
}
//安裝日志鉤子,輸出調(diào)試信息到文件,便于調(diào)試
void SaveLog::start()
{
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
    qInstallMsgHandler(Log);
#else
    qInstallMessageHandler(Log);
#endif
}

c.在日志重定向中,攔截(RTU client) Sent Serial ADU:和(RTU client) Received ADU:關(guān)鍵字的日志,并將其內(nèi)容截取發(fā)送給mainwindow

void SaveLog::save(const QString &content)
{
    if(1)
    {
        QString msg = static_cast<QString>(content);
        std::cout << msg.toLocal8Bit().data() << std::endl;
        //方法改進(jìn):之前每次輸出日志都打開文件,改成只有當(dāng)日期改變時(shí)才新建和打開文件
        if(content.contains("(RTU client) Sent Serial ADU:"))
        {
            //(RTU client) Sent Serial ADU: 0xfe0300000029901b
            //std::cout << "SendMsg" << msg.toUtf8().data() << std::endl;
            msg = msg.remove(msg.indexOf("(RTU client) Sent Serial ADU:"),32);

            msg = msg.left(msg.size());
            msg = msg.toUpper();
            int n = msg.length();
            while(n-2 > 0)
            {
                n = n - 2;
                msg.insert(n," ");
            }
            emit sigModbusData(msg,0);
            //std::cout << "SendMsg:  " << msg.toLocal8Bit().data() << std::endl;
        }
        else if(content.contains("(RTU client) Received ADU:"))
        {
            //std::cout << "RecvMsg" << msg.toLocal8Bit().data() << std::endl;
            msg = msg.remove(msg.indexOf("(RTU client) Received ADU:"),28);
            msg = msg.left(msg.size()-1);
            msg = msg.toUpper();
            int n = msg.length();
            while(n-2 > 0)
            {
                n = n - 2;
                msg.insert(n," ");
            }
            emit sigModbusData(msg,1);
            //std::cout << "Received:  " << msg.toLocal8Bit().data() << std::endl;
        }
        else if(!content.contains("(RTU client)"))
        {
            if(this->fileName.isEmpty())
            {
                QString fileName = QString("%1/Log/%2_log_%3.txt").arg(path).arg(name).arg(QDATETIME);
                if (this->fileName != fileName) {
                    this->fileName = fileName;
                    if (file->isOpen()) {
                        file->close();
                    }

                    file->setFileName(fileName);
                    file->open(QIODevice::WriteOnly | QIODevice::Append | QFile::Text);
                }
            }
            QTextStream logStream(file);
            logStream << QString("%1--Debug     %2").arg(QDATETIME_zzz).arg(msg) << "\n";
        }
    }
}

d.綁定信號與槽,將接受到的modbus數(shù)據(jù)幀顯示在textBrowser上

//獲取modbus raw 數(shù)據(jù)幀
    connect(SaveLog::Instance(),&SaveLog::sigModbusData,this,&MainWindow::onModbusRawData);
//獲取modbus數(shù)據(jù)幀 0發(fā)送的數(shù)據(jù) 1接受的數(shù)據(jù)
void MainWindow::onModbusRawData(QString data, int type)
{
    QString color;
    QString text;
    if(type == 0)   //發(fā)送
    {
        text = "發(fā)送數(shù)據(jù)幀:";
        color = "#F37257";
    }
    else if(type == 1)  //接受
    {
        text = "接受數(shù)據(jù)幀:";
        color = "#1777D7";
    }
    // 設(shè)置文字(樣式+內(nèi)容)
    QString  str = QString("<font color=\"%1\">" +QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ")+ text + data + "</font>").arg(color);
    ui->textBrowser->append(str);
}

程序效果如下圖所示

qmodbus,QT開發(fā)筆記,qt,ui,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-782036.html

到了這里,關(guān)于【Qt Modbus通信】QModbus實(shí)現(xiàn)modbus的主機(jī)功能 源碼分享的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • LabVIEW實(shí)現(xiàn)Modbus-TCP通信

    LabVIEW實(shí)現(xiàn)Modbus-TCP通信

    Modbus協(xié)議是一種已廣泛應(yīng)用于當(dāng)今工業(yè)控制領(lǐng)域的通用通訊協(xié)議,按其格式可分為Modbus-RTU、Modbus-ASCII和Modbus-TCP。其中,前兩者適用于串行通信控制網(wǎng)絡(luò)中,例如RS485、RS232等,而Modbus-TCP主要應(yīng)用于基于以太網(wǎng)TCP/IP通信的控制網(wǎng)絡(luò)中。通過此協(xié)議,控制器相互之間、或控制器經(jīng)

    2024年02月15日
    瀏覽(34)
  • ESP32 使用RS485模塊實(shí)現(xiàn)Modbus通信(二)

    ESP32 使用RS485模塊實(shí)現(xiàn)Modbus通信(二)

    MODBUS是一種廣泛使用的工業(yè)通信協(xié)議,它允許通過串行線路在不同設(shè)備之間進(jìn)行通信和數(shù)據(jù)交換。RS485模塊是一個(gè)在ESP32上實(shí)現(xiàn)MODBUS協(xié)議的硬件。在本教程中,我們將使用RS485模塊在ESP32開發(fā)板上創(chuàng)建一個(gè)MODBUS主機(jī)和從機(jī)設(shè)備,并實(shí)現(xiàn)與MODBUS主機(jī)的通信。 多個(gè)Modbus(Server)從機(jī)設(shè)備

    2024年01月20日
    瀏覽(29)
  • Modbus RTU 、Modbus ASCII及Modbus TCP驅(qū)動(dòng)代碼,支持主機(jī)和從機(jī)兩種模式

    本篇博文分享一款開源的Modbus協(xié)議棧。 協(xié)議棧支持Modbus主機(jī)和從機(jī)兩種模式,并且支持兩種模式同時(shí)開啟。從機(jī)支持Modbus RTU 、Modbus ASCII及Modbus TCP 3種模式,主機(jī)現(xiàn)在只支持常用的Modbus RTU模式。 資源下載:https://download.csdn.net/download/m0_38106923/87997766 源文件 描述 FreeModbusmodb

    2024年02月12日
    瀏覽(21)
  • 用C++QT實(shí)現(xiàn)一個(gè)modbus rtu通訊程序框架

    下面是一個(gè)簡單的Modbus RTU通訊程序框架的示例,使用C++和QT來實(shí)現(xiàn): 具體的數(shù)據(jù)處理將根據(jù)需求進(jìn)行擴(kuò)展和實(shí)現(xiàn),如寫入數(shù)據(jù)和處理異常等。另外,需要根據(jù)實(shí)際情況設(shè)置正確的串口參數(shù)和設(shè)備地址,并確保與Modbus設(shè)備的正確連接。在編譯和運(yùn)行程序之前,還需要在項(xiàng)目的

    2024年02月06日
    瀏覽(27)
  • 【自動(dòng)化】在WPF應(yīng)用程序中使用MVVM框架實(shí)現(xiàn)Modbus協(xié)議通信

    Modbus是一種廣泛應(yīng)用于工業(yè)領(lǐng)域的通信協(xié)議,主要用于設(shè)備間的數(shù)據(jù)交換。在WPF應(yīng)用程序中,我們可以使用MVVM(Model-View-ViewModel)框架來實(shí)現(xiàn)Modbus協(xié)議的通信。本文將詳細(xì)介紹如何實(shí)現(xiàn)這一功能。 為了在WPF應(yīng)用程序中實(shí)現(xiàn)Modbus協(xié)議通信,我們需要安裝一些第三方庫??梢允褂?/p>

    2024年03月22日
    瀏覽(35)
  • Modbus通信從入門到精通_1_Modbus通信基礎(chǔ)

    Modbus通信從入門到精通_1_Modbus通信基礎(chǔ)

    關(guān)于Modbus通信的相關(guān)知識比較零碎,此處對查找到的知識點(diǎn)從 理論 , 通信協(xié)議 、 使用方法 方面進(jìn)行整理。 值得學(xué)習(xí)的博文:Modbus及調(diào)試用軟件介紹;Modbus協(xié)議和上位機(jī)應(yīng)用開發(fā)介紹 Modbus是一種第三方公開協(xié)議 ,采用主從結(jié)構(gòu),主控設(shè)備房稱為Modbus Master,從設(shè)備方稱為

    2024年02月13日
    瀏覽(97)
  • 嵌入式通信協(xié)議【Modbus】Modbus TCP的幀格式

    嵌入式通信協(xié)議【Modbus】Modbus TCP的幀格式

    Client request:例: 19 B2 00 00 00 06 06 03 00 27 00 02 上面是modbus客戶端發(fā)出的報(bào)文內(nèi)容,為modbus tcp/ip協(xié)議格式,其前面的六個(gè)字節(jié)為頭字節(jié)( header handle); 19 B2 00 00 00 06 19 B2? 00 00 00 06 兩個(gè)Client發(fā)出的檢驗(yàn)信息,Sever端只是需要將這兩個(gè)字節(jié)的內(nèi)容copy以后再放到response的報(bào)文的相應(yīng)位

    2024年02月05日
    瀏覽(151)
  • S7-200SMART 實(shí)現(xiàn)MODBUS TCP通信的具體方法示例(客戶端讀寫+服務(wù)器響應(yīng))

    S7-200SMART 實(shí)現(xiàn)MODBUS TCP通信的具體方法示例(客戶端讀寫+服務(wù)器響應(yīng))

    前面和大家介紹了MODBUS TCP的基本使用方法,具體可參考以下鏈接中的內(nèi)容: S7-200SMART實(shí)現(xiàn)MODBUS TCP通信(客戶端+服務(wù)器)的具體方法和步驟示例 本次繼續(xù)和大家分享S7-200SMART 中實(shí)現(xiàn)MODBUS TCP通信的具體方法 , 任務(wù)要求:

    2024年02月16日
    瀏覽(51)
  • C# Modbus通信從入門到精通(11)——調(diào)試軟件Modbus Slave和Modbus Poll的使用

    C# Modbus通信從入門到精通(11)——調(diào)試軟件Modbus Slave和Modbus Poll的使用

    我們在開發(fā)Modbus程序的時(shí)候,會需要測試以下我們寫的Modbus程序有沒有問題,這時(shí)候就需要使用到Modbus Slave和Modbus Poll這兩個(gè)軟件,Modbus Slave是模擬Modbus從站,Modbus Poll是模擬Modbus從站主站的, 一般情況下我們開發(fā)的Modbus主站程序,當(dāng)我們沒有硬件作為從站的時(shí)候,我們可以

    2024年02月06日
    瀏覽(96)
  • C# Modbus通信從入門到精通(21)——Modbus TCP協(xié)議原理

    C# Modbus通信從入門到精通(21)——Modbus TCP協(xié)議原理

    Modbus TCP是走網(wǎng)口的,也可以在同一時(shí)間內(nèi)有多個(gè)從站訪問主站,并且通過Modbus事務(wù)處理標(biāo)識來區(qū)分同一時(shí)刻的不同Modbus事務(wù),這是區(qū)別于Modbus ASCII和Modbus RTU的地方。 Modbus客戶端通常輸入Modbus服務(wù)器的IP地址和端口號來建立TCP連接,然后根據(jù)從站地址來確定具體訪問哪個(gè)從站

    2024年02月15日
    瀏覽(98)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包