在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于QT的Modbus RTU主站上位工具設計

CHANBAEK ? 來源:木南創智 ? 作者:尹家軍 ? 2022-12-13 14:39 ? 次閱讀

Modbus是一種常見的工業系統通訊協議。在我們的設計開發工作中經常使用到它。在這一篇中我們將簡單實現一個基于QT的Modbus RTU主站上位工具。

1、概述

??Modbus RTU主站應用很常見,有一些是通用的,有一些是專用的。而這里我們希望實現一個主要針對我們的產品調試的Modbus RTU主站工具。

??在開始軟件設計之前,我們先來簡略地分析一下,實現這樣一個Modbus RTU主站工具包含的主要內容有哪些。我們認為軟件需要如下幾個方面的內容:

(1)、串口參數的配置

??Modbus RTU通過串口來實現通訊,所以我們需要對串口相關的參數進行配置。對串口的配置主要是串口名、波特率、校驗位、數據位和停止位等。對于這些參數我們讓使用者可以根據需要選擇。

??而串口號,我們希望軟件可以自動搜索當前可用的串口列表。而且我們可以通過操作更新可用的串口列表。對串口的操作主要是串口的打開與關閉。

(2)、從站信息的配置

??我們實現Modbus RTU主站應用就是訪問從站的數據,所以我們需要在主站應用中配置從站的信息。主要有站地址、數據類型、數據格式等,我們將其設置為可以選擇。

讀取從站的參數配置,主要是起始地址、讀取的數量。寫從站參數的配置,主要是起始地址、寫入的數量以及寫入的數值。

(3)、對從站的操作

??Modbus RTU主站對從站的操作無非是讀從站數據和寫從站數據,我們通過制定讀寫的寄存器類型、起始地址、數量等通過按鈕操作來實現讀寫命令的發送。

??除了手動操作讀寫外,很多時候我們可能需要Modbus RTU主站自動周期性的讀取從站的數據。所以我們讓其可以選擇以多長的周期自動循環讀取。

(4)、對信息的顯示

??接收信息的顯示,作為一款工具軟件, 我們當然希望看到我們發給從站的命令究竟有沒有成功,最簡單的和直觀的辦法就是將接收到的信息顯示出來。對于Modbus RTU主站當然是顯示對應的地址的值。

??同樣的,我們有時候想要看到發送和接收到的原始報文,所以我們對發送和接收到的報文也作相應的顯示。

??對于個別數據有時候我們還希望看到他的變化趨勢,所以我們可以添加一個圖形顯示,用以顯示我們制定的數據的變化趨勢。

??運行狀態的顯示, 我們希望對操作的狀態進行反饋以指示操作的動作是否執行,所以我們需要狀態欄來實現這一需求。

2、界面設計

??根據上一節中分析的需求,我們先來設計軟件的界面。我們在QT中基于QMainWindow類生成一個操作界面,包括菜單欄、工具欄和狀態欄以滿足需求中對狀態顯示及操作命令的要求。

??而在中間顯示區域,我們將其劃分為2列。在左邊的一列從上到下設置:串口配置操作區域和讀寫從站的交互配置區域。在右側的一列從上到下設置:動態曲線顯示區域、收發消息顯示區域以及直接輸入報文發送命令的輸入區域。具體的界面設置如下圖所示:

??完成如上圖的布局后,我們可以選擇在屬性中配置控件的參數,也可以在代碼中添加相關的參數。在這里在代碼中通過初始化形式完成參數的設置。完成整個布局后我們先試著運行程序,正常運行則出現如下的界面:

??上圖就是完成布局后的運行界面,不過我們還沒有實現相應的編碼,所以目前尚不能實現我們第一節中所預想的功能。

3、編碼實現

??接下來這一小節,我們將來編碼實現相應的功能。我們主要將功能分為串口操作功能、從站操作功能以及信息顯示功能三個部分來實現。

3.1、串口操作功能

??對串口的操作首先就是對串口參數的設置。我們在代碼中對界面上的串口號、波特率、數據位、校驗位和停止位的ComboBox控件進行初始化。其中串口號通過自動搜索當前可用的串口來實現。具體的實現方式如下:

//搜索串口
void MainWindow::SearchSerialPorts()
{
    ui->comboBoxPort->clear();

    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        ui->comboBoxPort->addItem(info.portName());
    }
}

??對串口的操作主要是串口的打開和關閉,在這里因為是Modbus RTU主站應用,我們稱之為連接和斷開。建立或斷開與從站的連接實際就是對串口的配置與操作,只是針對Modbus RTU作了一些封裝,具體實現如下:

//串口連接
void MainWindow::on_actionConnect_triggered()
{
    if (!modbusDevice)
        return;

    modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,ui->comboBoxPort->currentText());
    modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,ui->comboBoxBaud->currentText().toInt());

    switch(ui->comboBoxParity->currentIndex())                   //設置奇偶校驗
    {
        case 0: modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::NoParity);break;
        default: break;
    }

    switch(ui->comboBoxData->currentIndex())                   //設置數據位數
    {
        case 1:modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,QSerialPort::Data8);break;
        default: break;
    }

    switch(ui->comboBoxStop->currentIndex())                     //設置停止位
    {
        case 1: modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::OneStop);break;
        case 2: modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::TwoStop);break;
        default: break;
    }

    modbusDevice->setTimeout(1000);
    modbusDevice->setNumberOfRetries(3);

    if (modbusDevice->connectDevice())
    {
        //開啟自動讀取
        if(ui->checkBoxAuto->isChecked())
        {
            connect(pollTimer,&QTimer::timeout, this, &MainWindow::ReadRequest);
            pollTimer->setInterval(ui->spinBoxInterval->value());
            pollTimer->start();
        }

        //連接槽函數
        //QObject::connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::ReadSerialData);

        // 設置控件可否使用
        ui->actionConnect->setEnabled(false);
        ui->actionDisconnect->setEnabled(true);
        ui->actionRefresh->setEnabled(false);
    }
    else    //打開失敗提示
    {

        QMessageBox::information(this,tr("錯誤"),tr("連接從站失敗!"),QMessageBox::Ok);
    }
}

3.2、從站操作功能

??在前面一節中我們已經設計過,對從站的操作包括手動按鈕讀取從站數據、手動按鈕寫入從站數據以及自動周期讀取從站數據。

??手動讀取從站數據是指點擊按鈕時觸發一次讀從站的操作,而從站的地址、讀取的寄存器類型、讀取的寄存器起始地址和寄存器的數量均根據界面上相應的設置確定。具體的實現如下:

//讀數據請求
void MainWindow::ReadRequest()
{
    if (!modbusDevice)
    {
        QMessageBox::information(NULL,  "Title",  "尚未連接從站設備");
        return;
    }

    QModbusDataUnit::RegisterType type;

    switch(ui->comboBoxDataType->currentIndex())
    {
        case 0:type=QModbusDataUnit::Coils;break;
        case 1:type=QModbusDataUnit::DiscreteInputs;break;
        case 2:type=QModbusDataUnit::InputRegisters;break;
        case 3:type=QModbusDataUnit::HoldingRegisters;break;
        default:type=QModbusDataUnit::Invalid;
    }

    int startAddress = ui->spinBoxStartRead->value();
    Q_ASSERT(startAddress >= 0 && startAddress < 10);

    // do not go beyond 10 entries
    quint16 numberOfEntries = qMin(quint16(ui->spinBoxNumberRead->value()), quint16(10 - startAddress));
    QModbusDataUnit readUnit=QModbusDataUnit(type, startAddress, numberOfEntries);

    statusBar()->clearMessage();

    if (auto *reply = modbusDevice->sendReadRequest(readUnit, ui->spinBoxStation->value()))
    {
        if (!reply->isFinished())
            connect(reply, &QModbusReply::finished, this, &MainWindow::ReadSerialData);
        else
            delete reply; // broadcast replies return immediately
    }
    else
    {
        statusBar()->showMessage(tr("Read error: ") + modbusDevice->errorString(), 5000);
    }

}

??手動寫從站操作是指點擊按鈕觸發一次寫從站操作,而從站的地址、寫入的寄存器類型、寫入的寄存器起始地址、寫入的寄存器的數量以及寫入的值均根據界面上相應的設置確定。而寄存器的值得輸入以“,”分割,具體的實現如下:

//寫數據請求
void MainWindow::WriteRequest(QList values)
{
    if (!modbusDevice)
    {
        QMessageBox::information(NULL,  "Title",  "尚未連接從站設備");
        return;
    }

    QModbusDataUnit::RegisterType type;

    switch(ui->comboBoxDataType->currentIndex())
    {
        case 0:type=QModbusDataUnit::Coils;break;
        case 1:type=QModbusDataUnit::DiscreteInputs;break;
        case 2:type=QModbusDataUnit::InputRegisters;break;
        case 3:type=QModbusDataUnit::HoldingRegisters;break;
        default:type=QModbusDataUnit::Invalid;
    }

    int startAddress = ui->spinBoxStartWrite->value();
    Q_ASSERT(startAddress >= 0 && startAddress < 10);

    QModbusDataUnit writeUnit = QModbusDataUnit(type,startAddress, values.size());
    for(int i=0; isize(); i++)
    {
        writeUnit.setValue(i, values.at(i));
    }

    //serverEdit 發生給slave的ID
    if (auto *reply = modbusDevice->sendWriteRequest(writeUnit,ui->spinBoxStation->value()))
    {
        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());
    }
}

??對于自動周期性讀取從站數據我們通過一個計時器周期性操作,而從站的地址、讀取的寄存器類型、讀取的寄存器起始地址、寄存器的數量以及間隔時間通過界面設置。而其操作與手動按鈕觸發一樣。

3.3、信息顯示功能

??對于信息的顯示我們主要考慮3個方面的內容。一是讀取回來的從站數據結果顯示;二是上下行報文的監視;三是操作過程及狀態的顯示。

??首先是對讀取回來的從站數據進行顯示,在這里我們將讀取的寄存器地址及其對應的數據顯示在消息框中。同時我們將部分數據在圖形顯示中以曲線的形式展示出來。

//曲線顯示
void MainWindow::ChartDisplay()
{
    QColor acolor[8]={Qt::red,Qt::blue,Qt::green,Qt::cyan,Qt::yellow,Qt::magenta,Qt::black,Qt::darkRed};
    QStringList name={"拋物線","正弦值","正弦值","固定值","固定值","固定值","固定值","固定值"};
    QVector list[8];
    QVector newlist[8];

    for(int j=0;j<8;j++)
    {
        list[j] = lineSeries[j]->pointsVector();//獲取現在圖中列表

        if (list[j].size() < 200)
        {
            //保持原來
            newlist[j] = list[j];
        }
        else
        {
            //錯位移動
            for(int i =1 ; i< list[j].size();i++)
            {
                newlist[j].append(QPointF(i-1,list[j].at(i).y()));
            }
        }

        newlist[j].append(QPointF(newlist[j].size(),values[j]));//最后補上新的數據

        lineSeries[j]->replace(newlist[j]);//替換更新

        lineSeries[j]->setName(name[j]);//設置曲線名稱
        lineSeries[j]->setPen(acolor[j]);//設置曲線顏色
        lineSeries[j]->setUseOpenGL(true);//openGl 加速

        //mChart->setTitle("Pressure Data");//設置圖標標題
        mChart->removeSeries(lineSeries[j]);
        mChart->addSeries(lineSeries[j]);
        mChart->createDefaultAxes();//設置坐標軸
    }

    ui->graphicsView->setChart(mChart);
}

??其次對于上下行報文我們也將其顯示到消息顯示框中。在QT對Modbus協議進行封裝后,我們沒有辦法直接獲取上下行的報文,我們可以開啟日志答應功能,再從其中截取相應的報文。

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

??而操作過程及狀態顯示則比較簡單,我們在狀態欄顯示相應的操作過程和操作的狀態。

4、小結

??完成了編碼調試后,我們尚需要對這一工具進行一些測試。首先我們安裝一個虛擬串口軟件用以虛擬我們用于測試的串口,并找到一款Modbus RTU的從站模擬軟件。當然有實際的從站和硬件的串行端口更好,在這里我們先用軟件模擬。具體的配置如下圖所示:

??而Modbus RTU從站我們使用MThings來模擬,當然也可以使用其它Modbus RTU從站模擬軟件。我們模擬10個保持寄存器和10個線圈,之所以這么設置是因為這兩種數據類型支持讀寫,方便我們測試。具體的配置如下圖所示:

??現在將我們設計的Modbus RTU主站運行起來,并使用它去訪問我們剛才配置的Modbus RTU從站。首先我們實驗讀從站數據操作。測試的結果如下圖所示:

??這里我們讀取從站從地址0開始的10個保持寄存器,并將值顯示在消息框和圖形中。我們模擬了2路正弦信號、1路拋物線信號和5路固定值信號。接下來我們測試一下寫操作。測試的結果如下圖所示:

??這里對從站的從地址3開始的3個保持寄存器的值進行修改。設定的值分別是123、456和789,操作完成后我們查看從站的結果如下:

??上圖中與我們設定值的完全符合,說明我們的寫從站操作時正確的。到這里我們基于QT的Modbus RTU主站就基本實現了。當然,我們還可以根據需要修改或添加一些功能以適應不同的應用需求。我們已經將代碼發布到Gitee,歡迎下載和交流。

下載地址:https://gitee.com/ErichMoonan/ModbusMaster

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • MODBUS
    +關注

    關注

    28

    文章

    1805

    瀏覽量

    77003
  • 通訊協議
    +關注

    關注

    10

    文章

    274

    瀏覽量

    20354
  • Qt
    Qt
    +關注

    關注

    1

    文章

    304

    瀏覽量

    37922
  • RTU
    RTU
    +關注

    關注

    0

    文章

    413

    瀏覽量

    28680
收藏 人收藏

    評論

    相關推薦

    請教 labview 做一個modbus RTU

    最近在用LabVIE想做一個modbus RTu站,我的步驟是1、新建工程,2、新建一個 IO server,選擇modbus (串口,)3、新建一個VI現在有幾疑問,1、我通過這樣
    發表于 11-17 17:09

    【NanoPi M2試用體驗】之Modbus-RTU站開發

    NanoPi M2試用體驗之Modbus-RTU站開發本菜鳥之前的幾篇使用報告介紹了基于NanoPi M2無線網卡設置、NFS文件系統搭建、Mysql安裝、Mysql可視化配置,以及基于QT
    發表于 05-26 09:20

    Modbus站問題

    ModbusRTU兩站之間如何交互數據? 工業控制中,一般都是主從通訊方式居多,有時也會碰到兩個站之間通訊。例如某工作站上位機(站)需要監控一個plc末端設備,常規來說plc應作
    發表于 11-24 16:36

    請問在STM32上跑modbus rtu站應該怎么做

    最近一個項目中需要用到485通信,下面的期間是modbus rtu協議,我是小白沒搞過modbus,有沒有移植過的大神給小弟指點迷津啊,要在STM32上跑modbus
    發表于 01-11 09:04

    如何快速實現Modbus RTUModbus TCP協議轉換?

    Modbus協議是工業現場串口設備之間常用的連接方式,其中最常見的就是Modbus RTUModbus TCP兩種。許多工廠需要將現場各種不同型號設備的數據都能夠通過一個
    發表于 08-18 18:36

    上位MODBUS RTU多從站通訊的VB程序

    上位MODBUS RTU多從站通訊的VB程序,實現上位機與下位機之間的數據傳輸。
    發表于 10-12 16:05 ?77次下載

    淺談ModBus RTUModBus TCP

    ModBus RTUModBus TCP作為ModBus協議的兩個主要變體,傳統上,ModBus RT
    的頭像 發表于 12-30 14:36 ?2352次閱讀

    C#上位機:Modbus RTU通訊實例

    本文是對前文的補充,主要是針對上位機的串口通訊在Modbus RTU協議方面的運用。在前文中有詳細代碼描述了如何搭建一個串口通訊上 位機模板,在本文中,給出一些在前文中代碼基礎上的Modbu
    發表于 05-09 14:38 ?6次下載
    C#<b class='flag-5'>上位</b>機:<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>通訊實例

    EtherNet/IP轉Modbus-RTU站協議網關(JM-EIP-RTU

    RTU網絡之間無縫內部連接。 廣泛應用:應用于Modbus RTU接口的變頻器、上位機、儀表、馬保等等。例如在房山某污水處理廠的PLC控制系統項目中,羅克韋爾PLC作為EtherNe
    的頭像 發表于 08-26 14:43 ?321次閱讀
    EtherNet/IP轉<b class='flag-5'>Modbus-RTU</b><b class='flag-5'>主</b>站協議網關(JM-EIP-<b class='flag-5'>RTU</b>)

    EtherNet/IP轉Modbus-RTU站網關(EtherNet/IP轉Modbus-RTU

    RTU網絡之間無縫內部連接。 廣泛應用:應用于Modbus RTU接口的變頻器、上位機、儀表、馬保等等。例如在房山某污水處理廠的PLC控制系統項目中,羅克韋爾PLC作為EtherNe
    的頭像 發表于 09-04 10:55 ?297次閱讀
    EtherNet/IP轉<b class='flag-5'>Modbus-RTU</b><b class='flag-5'>主</b>站網關(EtherNet/IP轉<b class='flag-5'>Modbus-RTU</b>)

    Modbus RTU轉CC-Link協議網關(CC-Link轉Modbus RTU

    遠創智控YC-CCLK-RTU型網關實現了CC-Link從站和Modbus RTU站(從站)。網關作為CC-Link從站接入到CC-Link網絡中,比如連接到三菱PLC。CCLK-
    的頭像 發表于 09-07 14:59 ?451次閱讀
    <b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>轉CC-Link協議網關(CC-Link轉<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>)

    CC-Link IEFB站轉Modbus RTU協議網關(YC-CCLKIEM-RTU

    一,設備主要功能 遠創智控YC-CCLKIEM-RTU型網關在CC-Link IEFB總線側實現站功能,在Modbus RTU串口側實現從站功能。可將CC-Link IEFB協議的設
    的頭像 發表于 09-09 15:58 ?258次閱讀
    CC-Link IEFB<b class='flag-5'>主</b>站轉<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>協議網關(YC-CCLKIEM-<b class='flag-5'>RTU</b>)

    EtherCAT站轉Modbus RTU網關(EtherCAT轉Modbus RTU

    一,設備主要功能 遠創智控YC-ECTM-RTU型網關將EtherCAT協議的設備接入到Modbus RTU網絡中;可將EtherCAT站接入Mo
    的頭像 發表于 09-09 16:32 ?287次閱讀
    EtherCAT<b class='flag-5'>主</b>站轉<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>網關(EtherCAT轉<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>)

    Modbus RTU轉CC-link協議網關(Modbus RTU轉CC-link)

    一,設備主要功能 捷米特JM-CCLK-RTU網關實現CC-Link從站和Modbus RTU站(從站)。即將CC-Link作為CC-Link從站接入到
    的頭像 發表于 09-10 10:28 ?656次閱讀
    <b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>轉CC-link協議網關(<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>轉CC-link)

    EtherCAT轉 4 路Modbus RTU網關-三格電子

    ModbusRTU站如PLC、上位機等。 使用場景1:EtherCAT站讀寫Modbus RTU從站: 使用場景2:EtherCAT
    的頭像 發表于 12-25 17:25 ?78次閱讀
    EtherCAT轉 4 路<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>網關-三格電子
    主站蜘蛛池模板: 亚洲人成a在线网站| 8050午夜一级二级全黄| 99精品久久久久久久婷婷| 国产深夜福利在线观看网站| 欧美性色黄大片四虎影视| 色.com| 夜夜操夜夜操| 一区二区三区中文国产亚洲| 日日噜噜噜夜夜爽爽狠狠视频| freesexvideo性欧美医生护士| 35pao免费视频| 亚洲永久网站| 三级黄色片在线播放| 又黑又长黑人欧美三级| kkk4444免费观看| 日本一线a视频免费观看| 午夜韩国理论片在线播放| 亚洲一区二区三区在线播放| 琪琪see色原网一区二区| 天天插天天操天天射| 老师叫我揉她内裤越快越好| 美女网站黄页| 国产午夜在线视频| 亚洲色图在线观看视频| 播放毛片| 天天色成人网| 精品伊人久久大线蕉地址| good韩国理论在线三级| 色综合成人网| 天天干天天色综合网| 综合激情五月婷婷| 丁香5月婷婷| 亚洲国产日韩女人aaaaaa毛片在线| 女人张开腿男人桶| 国产又粗又大又爽又免费| 天堂在线精品| 天天爽夜夜爽精品视频一| 伊人久久大| 午夜在线一区| 在线观看中文字幕第一页| avtt加勒比手机版天堂网|