0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

使用協(xié)議棧實(shí)現(xiàn)Modbus TCP服務(wù)器應(yīng)用

CHANBAEK ? 來(lái)源:木南創(chuàng)智 ? 作者:尹家軍 ? 2022-12-13 16:23 ? 次閱讀

自從開(kāi)源了我們自己開(kāi)發(fā)的Modbus協(xié)議棧之后,有很多朋友建議我針對(duì)性的做幾個(gè)示例。所以我們就基于平時(shí)我們的應(yīng)用整理了幾個(gè)簡(jiǎn)單但可以說(shuō)明基本的應(yīng)用方法的示例,這一篇中我們來(lái)簡(jiǎn)述如何使用協(xié)議棧實(shí)現(xiàn)一個(gè)Modbus TCP服務(wù)器應(yīng)用。

1 、何為TCP服務(wù)器

Modbus協(xié)議是一個(gè)主從協(xié)議,那肯定就有主站和從站之分,在Modbus TCP中亦稱之為客戶端與服務(wù)器。所謂TCP客戶端其功能基本與RTU主站一樣,RTU主站會(huì)向從站發(fā)起數(shù)據(jù)請(qǐng)求,同樣的TCP客戶端也會(huì)向服務(wù)器發(fā)起請(qǐng)求。也就是說(shuō)在Modbus TCP模式下客戶端亦是發(fā)起通訊的一方。

對(duì)于TCP客戶端來(lái)說(shuō),自己并不會(huì)產(chǎn)生數(shù)據(jù),它的數(shù)據(jù)均是從服務(wù)器獲取,為了得到數(shù)據(jù)就必須向服務(wù)器發(fā)起數(shù)據(jù)請(qǐng)求。在Modbus TCP協(xié)議中,服務(wù)器一般也不會(huì)主動(dòng)向外發(fā)送數(shù)據(jù),服務(wù)器需要根據(jù)客戶端的數(shù)據(jù)請(qǐng)求來(lái)決定是否發(fā)送數(shù)據(jù)、發(fā)送哪些數(shù)據(jù)。這一過(guò)程如下圖所示:

從上圖我們不難看出,首先客戶端要主動(dòng)發(fā)起數(shù)據(jù)請(qǐng)求,客戶端發(fā)起的數(shù)據(jù)請(qǐng)求需要告訴服務(wù)器它請(qǐng)求的數(shù)據(jù)有哪些。服務(wù)器收到這個(gè)數(shù)據(jù)請(qǐng)求后,服務(wù)器解析客戶端的請(qǐng)求并按照客戶端的請(qǐng)求返回?cái)?shù)據(jù)。客戶端收到數(shù)據(jù)響應(yīng)后解析數(shù)據(jù),這樣就完成了客戶端與服務(wù)器之間的一次數(shù)據(jù)通訊。

需要注意的是,Modbus TCP與Modbus RTU不同的是有一個(gè)專(zhuān)用的MBAP報(bào)文頭來(lái)識(shí)別Modbus應(yīng)用數(shù)據(jù)單元。這一報(bào)文頭由7個(gè)字節(jié)組成:

這種MBAP報(bào)文頭雖然也是用來(lái)識(shí)別Modbus數(shù)據(jù)域,但還是與串行鏈路上使用的MODBUS RTU應(yīng)用數(shù)據(jù)單元有一些差別,具體如下:

1 、用MBAP報(bào)文頭中的單個(gè)字節(jié)單元標(biāo)識(shí)符取代MODBUS串行鏈路上通常使用的MODBUS從地址域。這個(gè)單元標(biāo)識(shí)符用于設(shè)備的通信,這些設(shè)備使用單個(gè) IP 地址支持多個(gè)獨(dú)立MODBUS 終端單元,例如:網(wǎng)橋、路由器和網(wǎng)關(guān)。

2 、使用接收者可以驗(yàn)證的方式來(lái)構(gòu)造所有MODBUS請(qǐng)求和響應(yīng)。對(duì)于MODBUS PDU有固定長(zhǎng)度的功能碼來(lái)說(shuō),僅功能碼就足夠了。對(duì)于在請(qǐng)求或響應(yīng)中攜帶一個(gè)可變數(shù)據(jù)的功能碼來(lái)說(shuō),數(shù)據(jù)域包括字節(jié)數(shù)。

3 、使用TCP上傳送MODBUS數(shù)據(jù)域時(shí),即使將報(bào)文分成多個(gè)信息包來(lái)傳輸,可在MBAP報(bào)文頭上攜帶附加長(zhǎng)度信息,這樣接收者就能夠識(shí)別報(bào)文的完整性。

2 、如何實(shí)現(xiàn)TCP服務(wù)器

我們已經(jīng)簡(jiǎn)單的描述了基于TCP/IP的Modbus數(shù)據(jù)通訊,在此基礎(chǔ)上我們將進(jìn)一步描述基于協(xié)議棧的Modbus TCP服務(wù)器的實(shí)現(xiàn)。

在協(xié)議棧中,我們已經(jīng)實(shí)現(xiàn)了Modbus TCP服務(wù)器的基本功能,如數(shù)據(jù)的管理及響應(yīng)客戶端的請(qǐng)求等。Modbus TCP服務(wù)器作為數(shù)據(jù)的生產(chǎn)者,管理者四類(lèi)數(shù)據(jù):線圈量、狀態(tài)量、輸入寄存器和保持寄存器。所以在Modbus TCP服務(wù)器中我們要為這四種數(shù)據(jù)定義相應(yīng)的地址,以便客戶端能夠?qū)?yīng)的訪問(wèn)。所以設(shè)計(jì)一個(gè)Modbus TCP服務(wù)器我們先來(lái)設(shè)計(jì)它的數(shù)據(jù)地址。在我們的例子中,出于操作方便,我們規(guī)定了每類(lèi)數(shù)據(jù)類(lèi)型的數(shù)量為10,我們以用的最多的保持寄存器為例,定義寄存器地址為40001到40010。

在我們的協(xié)議棧中實(shí)現(xiàn)了0x01、0x02、0x03、0x04、0x05、0x06、0x0F以及0x10等功能碼。也就是說(shuō)客戶端對(duì)象會(huì)生成面向這些功能碼的Modbus TCP服務(wù)器數(shù)據(jù)請(qǐng)求。Modbus TCP服務(wù)器收到請(qǐng)求后,解析請(qǐng)求并根據(jù)請(qǐng)求生成響應(yīng)的數(shù)據(jù)響應(yīng)??梢员硎緸橄聢D所示:

從上圖我們明白協(xié)議棧中已經(jīng)實(shí)現(xiàn)了對(duì)收到的主站數(shù)據(jù)請(qǐng)求進(jìn)行解析以及根據(jù)解析生成對(duì)應(yīng)的響應(yīng)的函數(shù)。我們使用協(xié)議棧時(shí),主要需要做兩個(gè)方面的事情:解析數(shù)據(jù)請(qǐng)求和生成數(shù)據(jù)響應(yīng)。

在協(xié)議棧中定義了一個(gè)解析函數(shù),該函數(shù)將收到的數(shù)據(jù)請(qǐng)求消息解析,并根據(jù)解析的結(jié)果生成返回的數(shù)據(jù)響應(yīng)。該函數(shù)的原型如下:

/ 解析接收到的信息,返回響應(yīng)命令的長(zhǎng)度 /

uint16_t ParsingClientAccessCommand(uint8_t receivedMessage,uint8_trespondBytes)

這個(gè)函數(shù)有2個(gè)參數(shù):uint8_t receivedMessage是收到的數(shù)據(jù)請(qǐng)求消息; uint8_trespondBytes是返回的數(shù)據(jù)響應(yīng)消息,也是函數(shù)需要生成的;而函數(shù)的返回值則是生成的數(shù)據(jù)響應(yīng)詳細(xì)的長(zhǎng)度。

在解析的過(guò)程中,該函數(shù)判斷消息的完整性,并根據(jù)不同的功能碼調(diào)用不同的回調(diào)函數(shù)來(lái)實(shí)現(xiàn),包括設(shè)置本地?cái)?shù)據(jù)和獲取本地?cái)?shù)據(jù)的相關(guān)回調(diào)函數(shù),在后續(xù)將討論它們的實(shí)現(xiàn)。

3 、 TCP****服務(wù)器編碼

到這里其實(shí)我們已經(jīng)很清楚,使用協(xié)議棧實(shí)現(xiàn)Modbus TCP服務(wù)器只需要在TCP/IP收到客戶端請(qǐng)求后調(diào)用sendLen = ParsingClientAccessCommand(buffer,sendBuf);函數(shù)解析收到的請(qǐng)求命令。并根據(jù)請(qǐng)求執(zhí)行相應(yīng)的操作就可以了。那需要實(shí)現(xiàn)哪些操作呢?在協(xié)議棧中定義了8個(gè)回調(diào)函數(shù),分別是獲取線圈量、獲取狀態(tài)量、獲取輸入寄存器和獲取保持寄存器,以及預(yù)置單個(gè)線圈量、預(yù)置多個(gè)線圈量、預(yù)置單個(gè)保持寄存器和預(yù)置多個(gè)保持寄存器。函數(shù)原型定義如下:

/*獲取想要讀取的Coil量的值*/
__weak void GetCoilStatus(uint16_t startAddress,uint16_t quantity,bool*statusList)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*獲取想要讀取的InputStatus量的值*/
__weak void GetInputStatus(uint16_t startAddress,uint16_t quantity,bool*statusValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*獲取想要讀取的保持寄存器的值*/
__weak void GetHoldingRegister(uint16_t startAddress,uint16_t quantity,uint16_t*registerValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*獲取想要讀取的輸入寄存器的值*/
__weak void GetInputRegister(uint16_t startAddress,uint16_tquantity,uint16_t *registerValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*設(shè)置單個(gè)線圈的值*/
__weak void SetSingleCoil(uint16_t coilAddress,bool coilValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*設(shè)置單個(gè)寄存器的值*/
__weak void SetSingleRegister(uint16_t registerAddress,uint16_tregisterValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*設(shè)置多個(gè)線圈的值*/
__weak void SetMultipleCoil(uint16_t startAddress,uint16_t quantity,bool*statusValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}
 
/*設(shè)置多個(gè)寄存器的值*/
__weak void SetMultipleRegister(uint16_t startAddress,uint16_tquantity,uint16_t *registerValue)
{
  //如果需要Modbus TCP Server/RTU Slave應(yīng)用中實(shí)現(xiàn)具體內(nèi)容
}

這些函數(shù)就是我們要根據(jù)我們的Modbus TCP服務(wù)器功能設(shè)計(jì)實(shí)現(xiàn)的。對(duì)于我們這個(gè)測(cè)試?yán)游覀冎恍枰獙?shí)現(xiàn)讀取保持寄存器就可以了。具體實(shí)現(xiàn)如下:

/*獲取想要讀取的保持寄存器的值*/
void GetHoldingRegister(uint16_t startAddress,uint16_t quantity, uint16_t* registerValue)
{
   uint16_t start;
   uint16_t count;
   
    /*先判斷地址是否處于合法范圍*/
    start =(startAddress > 0) ? ((startAddress <= 9) ? startAddress : 9) : 0;
    count =((start + quantity - 1) <= 9) ? quantity : (9 - start);
 
    for(int i = 0; i < count; i++)
    {
       registerValue[i] = holdingRegister[start + i];
    }
}

這個(gè)例子中我們實(shí)現(xiàn)了讀取40001到40010保持寄存器的值。

4 、 TCP****服務(wù)器小結(jié)

我們?cè)赥CP服務(wù)器的基礎(chǔ)上使用我們的協(xié)議棧實(shí)現(xiàn)一個(gè)Modbus TCP服務(wù)器應(yīng)用。其實(shí)使用協(xié)議棧實(shí)現(xiàn)Modbus TCP服務(wù)器應(yīng)用是很簡(jiǎn)單的,我們需要使用如ModPoll這樣的軟件來(lái)測(cè)試一下它。

我們讀取10個(gè)保持寄存器,值分別為對(duì)應(yīng)位固定的1到10,如上圖讀出的結(jié)果與預(yù)期一致。我們還可以采用TCP&UDP測(cè)試工具來(lái)看一下報(bào)文,具體如下:

同樣的,在同一臺(tái)設(shè)備上只需實(shí)現(xiàn)一個(gè)Modbus TCP服務(wù)器,哪怕是通過(guò)不同的網(wǎng)絡(luò)端口來(lái)訪問(wèn)。這一點(diǎn)與客戶端是不一樣的,原因是Modbus TCP服務(wù)器的數(shù)據(jù)是自己產(chǎn)生,而且只需被動(dòng)響應(yīng)客戶端的數(shù)據(jù)請(qǐng)求。

接下來(lái)我們來(lái)總結(jié)一下使用協(xié)議棧實(shí)現(xiàn)Modbus TCP服務(wù)器的工作流程,或者說(shuō)實(shí)現(xiàn)的步驟。首先Modbus TCP服務(wù)器要解析從客戶端送來(lái)的數(shù)據(jù)請(qǐng)求。在協(xié)議棧中已經(jīng)封裝了數(shù)據(jù)請(qǐng)求的解析函數(shù)、所以我們實(shí)現(xiàn)Modbus TCP服務(wù)器時(shí)首先就是調(diào)用這一函數(shù)來(lái)解析接收到的數(shù)據(jù)請(qǐng)求消息。

然后將解析函數(shù)返回的數(shù)據(jù)響應(yīng)消息發(fā)送到客戶端就可以了。也就是說(shuō)使用協(xié)議棧,只需要調(diào)用一下這個(gè)函數(shù)Modbus TCP服務(wù)器功能就實(shí)現(xiàn)了。這是因?yàn)檫@個(gè)函數(shù)實(shí)現(xiàn)了整個(gè)Modbus TCP服務(wù)器的響應(yīng)過(guò)程,大致分三個(gè)步驟:第一步,解析收到的客戶端數(shù)據(jù)請(qǐng)求消息;第二步,根據(jù)解析的結(jié)果預(yù)置數(shù)據(jù)或者獲取數(shù)據(jù),預(yù)置和獲取數(shù)據(jù)由8個(gè)回調(diào)函數(shù)實(shí)現(xiàn);第三步,生成Modbus TCP服務(wù)器數(shù)據(jù)響應(yīng)消息。說(shuō)到這里我們已經(jīng)清楚,Modbus TCP服務(wù)器必須實(shí)現(xiàn)這些回調(diào)函數(shù),其它工作則全由協(xié)議棧完成。

源碼下載:https://download.csdn.net/download/foxclever/12838885

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • MODBUS
    +關(guān)注

    關(guān)注

    28

    文章

    1805

    瀏覽量

    76992
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    9160

    瀏覽量

    85415
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1353

    瀏覽量

    79070
  • 協(xié)議棧
    +關(guān)注

    關(guān)注

    2

    文章

    141

    瀏覽量

    33631
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    使用協(xié)議實(shí)現(xiàn)Modbus TCP客戶端應(yīng)用

    自從開(kāi)源了我們自己開(kāi)發(fā)的Modbus協(xié)議之后,有很多朋友建議我針對(duì)性的做幾個(gè)示例。所以我們就基于平時(shí)我們的應(yīng)用整理了幾個(gè)簡(jiǎn)單但可以說(shuō)明基本的應(yīng)用方法的示例,這一篇中我們將解說(shuō)如何使用協(xié)議
    的頭像 發(fā)表于 12-13 16:18 ?1769次閱讀
    使用<b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b><b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>Modbus</b> <b class='flag-5'>TCP</b>客戶端應(yīng)用

    linux平臺(tái)實(shí)現(xiàn)modbus主機(jī)協(xié)議的動(dòng)態(tài)庫(kù)libMbpoll

    libMbopll動(dòng)態(tài)庫(kù)是面向linux平臺(tái)設(shè)計(jì)的modbus主機(jī)協(xié)議,可以運(yùn)行在x86平臺(tái)以及各種嵌入式linux平臺(tái);協(xié)議提供了簡(jiǎn)單
    發(fā)表于 05-28 14:55

    協(xié)議介紹--TCP/IP

    ,和SOCKET API。以及DNS,PING等直接調(diào)用的函數(shù)。5)本協(xié)議可以完成客戶機(jī),服務(wù)器,UDP客戶機(jī),UDP服務(wù)器。還可以方便完成DNS客戶端功能,PING客戶端功能。6)
    發(fā)表于 09-03 15:03

    Modbus庫(kù)開(kāi)發(fā)筆記之九:利用協(xié)議開(kāi)發(fā)Modbus TCP Server應(yīng)用

    。接下來(lái)我們討論Modbus TCP Server的實(shí)現(xiàn)過(guò)程。根據(jù)前面對(duì)協(xié)議的封裝,我們需要引用ModbusTCP Server的相關(guān)封裝
    發(fā)表于 08-26 15:56

    Modbus協(xié)議中文版

    不同類(lèi)型的總線或網(wǎng)絡(luò)連接的設(shè)備之間的客 戶機(jī)/服務(wù)器通信。 目前,使用下列情況實(shí)現(xiàn) MODBUS: 以太網(wǎng)上的TCP/IP。 各種媒體(有線:EIA/TIA-232-E、EIA
    發(fā)表于 07-09 07:16

    在uIP協(xié)議實(shí)現(xiàn)基于AJAX和CGI的動(dòng)態(tài)Web服務(wù)器

    和應(yīng)用。為了滿足資源有限的嵌入式系統(tǒng)的需要,本文采用微型TCP/IP協(xié)議uIP,在協(xié)議之上設(shè)計(jì)實(shí)現(xiàn)
    發(fā)表于 05-28 05:00

    怎么實(shí)現(xiàn)的基于TCP/IP協(xié)議的簡(jiǎn)易服務(wù)器?

    本文以SPCE061A為主控制,DM9000為以太網(wǎng)MAC控制,配合一定的外圍電路而實(shí)現(xiàn)的基于TCP/IP協(xié)議
    發(fā)表于 05-31 06:34

    如何快速實(shí)現(xiàn)Modbus RTU和Modbus TCP協(xié)議轉(zhuǎn)換?

    整合起來(lái)監(jiān)控管理,目前上位機(jī)大部分用的Modbus TCP協(xié)議,而現(xiàn)場(chǎng)設(shè)備有大批量使用的是Modbus RTU協(xié)議,要
    發(fā)表于 08-18 18:36

    基于RT-Thread實(shí)現(xiàn)的Agile Modbus協(xié)議

    基于 RT-Thread 實(shí)現(xiàn)的支持 Modbus 固件升級(jí)的 Bootloader:HPM6750_Boot  特性  支持 rtu 及 tcp 協(xié)議,使用純 C 開(kāi)發(fā),不涉及任何硬
    發(fā)表于 10-08 15:04

    Modbus通訊協(xié)議的幾種實(shí)現(xiàn)方式

    量避免采用OPC。   OPC協(xié)議實(shí)現(xiàn)要通過(guò)兩部分完成。首先是OPC服務(wù)器,這是軟件程序與不同協(xié)議下工業(yè)設(shè)備通訊的中間件,相當(dāng)于網(wǎng)關(guān)。在OPC服務(wù)
    發(fā)表于 05-05 16:19

    嵌入式WEB服務(wù)器TCP/IP協(xié)議的設(shè)計(jì)與實(shí)現(xiàn)

    嵌入式TCP/IP 協(xié)議能擴(kuò)展非智能設(shè)備的網(wǎng)絡(luò)功能,是信息智能化的一種有效手段。 本文從嵌入式WEB 服務(wù)器入手,分析了嵌入式TCP
    發(fā)表于 06-19 09:03 ?35次下載

    Microchip TCP/IP協(xié)議

    的開(kāi)發(fā)人員可以很容易找到許多Microchip產(chǎn)品的商業(yè)和非商業(yè)的TC P/IP實(shí)現(xiàn)方案。本應(yīng)用筆記詳細(xì)說(shuō)明了Microchip公司自己免費(fèi)提供的TC P/IP協(xié)議。 Microchip T
    發(fā)表于 04-20 16:04 ?4次下載
     Microchip <b class='flag-5'>TCP</b>/IP<b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>

    STM32+ENC28J60+UIP協(xié)議實(shí)現(xiàn)WEB服務(wù)器示例

    STM32+ENC28J60+UIP協(xié)議實(shí)現(xiàn)WEB服務(wù)器示例
    發(fā)表于 12-06 09:21 ?34次下載
    STM32+ENC28J60+UIP<b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b><b class='flag-5'>實(shí)現(xiàn)</b>WEB<b class='flag-5'>服務(wù)器</b>示例

    Arduino供電的I/O Modbus/TCP設(shè)備服務(wù)器

    電子發(fā)燒友網(wǎng)站提供《Arduino供電的I/O Modbus/TCP設(shè)備服務(wù)器.zip》資料免費(fèi)下載
    發(fā)表于 11-24 14:27 ?0次下載
    Arduino供電的I/O <b class='flag-5'>Modbus</b>/<b class='flag-5'>TCP</b>設(shè)備<b class='flag-5'>服務(wù)器</b>

    串口服務(wù)器TCP/IP協(xié)議是什么關(guān)系

    串口服務(wù)器TCP/IP協(xié)議之間存在著緊密而復(fù)雜的關(guān)系。這種關(guān)系主要體現(xiàn)在串口服務(wù)器如何利用TCP
    的頭像 發(fā)表于 08-25 17:35 ?1562次閱讀