精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

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

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

3天內不再提示

使用協議棧實現Modbus TCP客戶端應用

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

自從開源了我們自己開發的Modbus協議棧之后,有很多朋友建議我針對性的做幾個示例。所以我們就基于平時我們的應用整理了幾個簡單但可以說明基本的應用方法的示例,這一篇中我們將解說如何使用協議棧實現一個Modbus TCP客戶端。

1 、何為TCP客戶端

Modbus協議是一個主從協議,那肯定就有主站和從站之分,在Modbus TCP中亦稱之為客戶端與服務器。所謂TCP客戶端其功能基本與RTU主站一樣,RTU主站會向從站發起數據請求,同樣的TCP客戶端也會向服務器發起請求。也就是說在Modbus TCP模式下客戶端亦是發起通訊的一方。

對于TCP客戶端來說,自己并不會產生數據,它的數據均是從服務器獲取,為了得到數據就必須向服務器發起數據請求。在Modbus TCP協議中,服務器一般也不會主動向外發送數據,服務器需要根據客戶端的數據請求來決定是否發送數據、發送哪些數據。這一過程如下圖所示:

從上圖我們不難看出,首先客戶端要主動發起數據請求,客戶端發起的數據請求需要告訴服務器它請求的數據有哪些。服務器收到這個數據請求后,服務器解析客戶端的請求并按照客戶端的請求返回數據。客戶端收到數據響應后解析數據,這樣就完成了客戶端與服務器之間的一次數據通訊。

需要注意的是,Modbus TCP與Modbus RTU不同的是有一個專用的MBAP報文頭來識別Modbus應用數據單元。這一報文頭由7個字節組成:

這種MBAP報文頭雖然也是用來識別Modbus數據域,但還是與串行鏈路上使用的MODBUS RTU應用數據單元有一些差別,具體如下:

1 、用MBAP報文頭中的單個字節單元標識符取代MODBUS串行鏈路上通常使用的MODBUS從地址域。這個單元標識符用于設備的通信,這些設備使用單個 IP 地址支持多個獨立MODBUS 終端單元,例如:網橋、路由器和網關。

2 、使用接收者可以驗證的方式來構造所有MODBUS請求和響應。對于MODBUS PDU有固定長度的功能碼來說,僅功能碼就足夠了。對于在請求或響應中攜帶一個可變數據的功能碼來說,數據域包括字節數。

3 、使用TCP上傳送MODBUS數據域時,即使將報文分成多個信息包來傳輸,可在MBAP報文頭上攜帶附加長度信息,這樣接收者就能夠識別報文的完整性。

2 、如何實現TCP客戶端

我們已經簡單的描述了基于TCP/IP的Modbus數據通訊,在此基礎上我們將進一步描述基于協議棧的Modbus TCP客戶端的實現。

在協議棧中,我們已經實現了TCP客戶端的數據請求命令的合成以及響應數據的解析,所以我們使用協議棧時就是要控制何時將協議棧合成的客戶端請求命令發出以及如何解析數據響應進而得到想要的數據的過程。

在我們的協議棧中實現了0x01、0x02、0x03、0x04、0x05、0x06、0x0F以及0x10等功能碼。也就是說TCP客戶端對象可以生成面向這些功能碼的服務器數據請求。也可以解析面向這些功能碼的服務器數據響應??梢员硎緸橄聢D所示:

從上圖我們很清楚,協議棧已經實現了面向這些功能碼的數據請求命令的生成以及數據響應消息的解析。我們使用協議棧時需要做的就是要告訴協議棧我要生成哪些數據請求命令以及如何解析數據響應消息。

2.1 、生成數據請求

作為客戶端需要主動向服務器發起操作,所以我們要控制客戶端生成可以被服務器識別的命令序列。在協議棧中已經封裝了生成客戶端訪問服務器的命令序列的函數,其原型如下:

/ 生成訪問服務器的命令 /

uint16_t CreateAccessServerCommand(TCPLocalClientType*client,ObjAccessInfo objInfo,void *dataList,uint8_t *commandBytes)

這個函數有4個參數,分別是:

TCPLocalClientType *client,所發起訪問的本地客戶端對象。

ObjAccessInfo objInfo,用于生成訪問命令的信息,如站地址、功能碼等。

void *dataList,如果是寫操作,則對應需要寫的數據列表,線圈為bool量、寄存器為uint16_t型無符號整數。

uint8_t *commandBytes是生成的命令序列

而返回值則是生成的命令序列的長度。在我們需要生成訪問服務器的命令時,調用這個函數就可實現。不過一定要注意生成的命令序列的長度,定義commandBytes對象時長度一定要足夠。

2.2 、解析數據響應

當客戶端收到服務器返回的響應信息后,客戶端需要對消息進行解析,并決定需要進行的操作。在協議棧中封裝了對服務器響應消息的解析函數,該函數的原型如下:

/ 解析收到的服務器相應信息 /

void ParsingServerRespondMessage(TCPLocalClientType client,uint8_trecievedMessage)

這一解析函數包含2個參數,TCPLocalClientType client是本地客戶端對象;而uint8_trecievedMessage為接收到的服務器響應消息。本函數會注意核對任務號、協議代碼、功能碼、數據完整性等,檢驗正確的消息會被解析,并根據消息來操作相應的數據對象,比如讀的是服務器的保持寄存器,則根據讀的起始地址和數量以及數據對象的類型來解析之。

3 TCP****客戶端編碼

我們講述了客戶端所要進行的工作以及協議棧中封裝好的面向客戶端的操作函數,接下來我們將基于協議棧來實現一個簡單的Modbus TCP客戶端實例。

3.1 、定義TCP客戶端對象

在開始實現客戶端的相關操作前,我們需要先聲明并實例化部分用于Modbus TCP客戶端操作的對象。

首先需要定義用于本地操作的本地客戶端,也就是我們要實現的客戶端對象。具體的聲明如下:TCPLocalClientType mbClient;

其次需要聲明一個或者多個服務器對象,這些服務器對象是我們所要實現的客戶端所管理的服務器對象。具體的聲明如下:TCPAccessedServerType mbServer;

同時需要定義一個用于存放讀操作命令的數組,定義一個寫服務器操作的線圈量對象數組和一個寄存器量對象數組,具體如下:

uint8_t readCommand[10][12];
WritedCoilListNode coilList[3]={{0,0,0,1},{1,0,0,1},{2,0,0,0}};
WritedRegisterListNoderegisterList[3]={{0,0,0,1,1},{1,0,0,1,2},{2,0,0,0,0}};

接下來還需要對客戶端對象和服務器對象進行初始化和實例化。而上述的數組將作為參數用于客戶端對象的初始化和服務器對象的實例化。

此外還要定義4個函數指針用于對從服務器讀取回來的數據進行更新,這幾個函數的原型如下:

/*更新讀回來的線圈狀態*/
typedef void (*UpdateCoilStatusType)(uint8_t salveAddress,uint16_tstartAddress,uint16_t quantity,bool *stateValue);


/*更新讀回來的輸入狀態值*/
typedef void (*UpdateInputStatusType)(uint8_t salveAddress,uint16_tstartAddress,uint16_t quantity,bool *stateValue);


/*更新讀回來的保持寄存器*/
typedef void (*UpdateHoldingRegisterType)(uint8_t salveAddress,uint16_tstartAddress,uint16_t quantity,uint16_t *registerValue);


/*更新讀回來的輸入寄存器*/
typedef void (*UpdateInputResgisterType)(uint8_t salveAddress,uint16_tstartAddress,uint16_t quantity,uint16_t *registerValue);

這幾個函數的實現要根據具體的參數來實現。定義好這些對象后,我們就可以對客戶端進行初始化和對服務器進行實例化。

/*初始化TCP客戶端對象*/
InitializeTCPClientObject(&mbClient, NULL, NULL, UpdateHoldingRegister, NULL);
/* 實例化TCP服務器對象 */
InstantiateTCPServerObject(&mbServer,          //要實例化的服務器對象
    &mbClient,             //服務器所屬本地客戶端對象
    192,                     //IP地址第1段
    168,                     //IP地址第2段
    183,                     //IP地址第3段
    130,                     //IP地址第4段
    502,
    1,
    rCmd,
    0,              //可寫線圈量節點的數量
    NULL,          //寫線圈列表
    0,          //可寫寄存器量節點的數量
    NULL);  //寫寄存器列表

在這一示例中,我們只定義了一個服務器所以只需要實例化一個就可以了,實例化函數會自動將服務器添加到客戶端管理的服務器列表中。

3.2 、生成客戶端數據請求

作為客戶端需要首先發起請求。在前一節我們已經講述了生成客戶端請求的函數。我們只需要調用該函數就可以了,但該函數需要一些參數,我們先來看看這些參數是否準備就緒。

第一個參數是客戶端對象,在前面的描述中我們已經生命并初始化完成了這一對象所以直接使用就好。

第二個參數是要生成請求的信息,其定義為一個結構體變量。

/*定義用于傳遞要訪問從站(服務器)的信息*/
typedef struct{
  uint8_t unitID;
  FunctionCode functionCode;
  uint16_t startingAddress;
  uint16_t quantity;
}ObjAccessInfo;

所以我們需要定義一個該類型變量,并根據我們的操作要求給其賦值。我們假設要實現對站地址為1的服務器對象的保持寄存器從0-9共10個寄存器地址的讀取則可實現為:

ObjAccessInfo tObj={1,ReadHoldingRegister,0x00,10};

第三個參數為數據列表,讀服務器時無數據列表以NULL輸入。第四個參數則為生成的讀服務器數據的請求命令,我們按要求定義即可使用,于是我們就可以調用該函數生成相應的命令了。

uint16_t sendLengh;
uint8_t sendCommand[12];
sendLengh=CreateAccessServerCommand(&tClient,tObj,NULL,sendCommand);

這一例子中我們是讀取服務器保持寄存器的數據,如果我們寫服務器對應數據,這只要將dataList組織好,作為參數傳入就好,不過要注意返回的命令的長度。生成訪問服務器的命令后,作為客戶端主動發送相應的命令后等待服務器響應。

3.3 、解析服務器數據響應

客戶端接收到服務器的返回信號后,就會調用解析函數對消息進行解析并根據具體的消息對數據對象進行更新。解析函數非常簡單僅有兩個參數,一個是本地客戶端對象,一個是接收到的響應消息。

ParsingServerRespondMessage(&tClient,recievedMessage);

解析函數會根據消息內容執行相應的操作。如在這個實例中,我們讀取了服務器的保持寄存器起始地址為0的10個寄存器,所以解析函數會調用保持寄存器數據處理函數來更新數據,最終其實就是以回調的方式執行。在這里我們將需要實現更新讀回來的保持寄存器的參數的函數。

/*更新讀回來的保持寄存器*/
void UpdateHoldingRegisterForClient(uint8_tserverAddress,uint16_t startAddress,uint16_t quantity,uint16_t *registerValue)
{
  uint16_tstartRegister=HoldingResterEndAddress+1;
 
 if(serverAddress==130)
  {
   startRegister=startAddress;
  }
 
  for(inti=0;i

至此我們實際已經實現了一個簡單的Modbus TCP客戶端。不過我們還要說明一下,使用不同的協議棧時,解析函數中的recievedMessage參數的具體的形式需要調整。

4 、 TCP****客戶端小結

我們使用協議棧完成了一個簡單的Modbus TCP客戶端應用實例。同樣的我們可以使用相關的Modbus測試軟件測試這一示例。我們使用Modbus Slave模擬Modbus TCP服務器應用,然后使用我們實現的客戶端與之通訊,以驗證我們的客戶端。

客戶端接收到的服務器反饋如下圖:

上圖說明我們基于協議棧實現的簡單Modbus TCP客戶端是正確的。在使用協議棧實現Modbus TCP客戶端時,我們需要注意,協議棧封裝了Modbus TCP客戶端,使得在同一臺設備上支持在不同的接口實現不同的客戶端,也就是在同一設備可以實現多個客戶端以管理不同的服務器。具體的實現可以根據協議棧進一步發揮。

最后我們來總結一下使用協議棧實現Modbus TCP客戶端應用的步驟,以方便大家使用協議棧實現Modbus TCP客戶端應用。

第一步,使用Modbus TCP客戶端對象類型聲明一個Modbus TCP客戶端對象。然后對這個Modbus TCP客戶端對象進行初始化。初始化Modbus TCP客戶端對象時。需要指定所管理的服務器的數量,服務器列表以及更新數據的回調函數指針。

第二步,生成訪問Modbus TCP客戶端的數據請求列表。這個數據請求列表是按每一臺服務器來劃分的,將列表的指針存在對應的服務器本地對象中。然后在需要的時候發送相應的數據請求。

第三步,解析接收的服務器數據響應。協議棧已經定義好了解析函數,只需傳入消息就可自動解析。但是更新數據的回調函數必須根據具體的變量來編寫。可以每臺Modbus TCP客戶端獨立編寫,也可使用默認的函數。

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

    關注

    28

    文章

    1760

    瀏覽量

    76833
  • TCP
    TCP
    +關注

    關注

    8

    文章

    1349

    瀏覽量

    78985
  • 客戶端
    +關注

    關注

    1

    文章

    290

    瀏覽量

    16661
  • 協議棧
    +關注

    關注

    2

    文章

    140

    瀏覽量

    33608
收藏 人收藏

    評論

    相關推薦

    Linux網絡編程-TCP客戶端如何獲取要連接的服務IP?

    本篇介紹了在TCP通信中,客戶端通過UDP廣播,實現自動獲取服務的IP地址,并進行TCP連接的具體方法,并通過代碼
    的頭像 發表于 09-27 08:56 ?3607次閱讀
    Linux網絡編程-<b class='flag-5'>TCP</b><b class='flag-5'>客戶端</b>如何獲取要連接的服務<b class='flag-5'>端</b>IP?

    Modbus TCP的設計與實現

    對于Modbus TCP來說與Modbus RTU和Modbus ASCII有比較大的區別,因為它是運行于以太網鏈路之上,是運行于TCP/I
    的頭像 發表于 12-13 15:33 ?2117次閱讀
    <b class='flag-5'>Modbus</b> <b class='flag-5'>TCP</b>的設計與<b class='flag-5'>實現</b>

    使用協議實現Modbus TCP服務器應用

    自從開源了我們自己開發的Modbus協議之后,有很多朋友建議我針對性的做幾個示例。所以我們就基于平時我們的應用整理了幾個簡單但可以說明基本的應用方法的示例,這一篇中我們來簡述如何使用協議
    的頭像 發表于 12-13 16:23 ?1531次閱讀
    使用<b class='flag-5'>協議</b><b class='flag-5'>棧</b><b class='flag-5'>實現</b><b class='flag-5'>Modbus</b> <b class='flag-5'>TCP</b>服務器應用

    求助!用labview的TCP傳輸協議傳輸的圖片不能在客戶端實時...

    求助!我編了用labviewTCP傳輸協議進行圖像采集傳輸的TCP客戶端和服務,客戶端和服務
    發表于 12-04 17:09

    labview TCP客戶端

    最近在做一個labview 客戶端測試小程序,服務器采用MFC編寫,客戶端采用TCP偵聽函數,通信可以連接,數據也正確,但是服務器檢測發送判斷失敗,個人推測是不是
    發表于 06-30 23:15

    協議介紹--TCP/IP

    ,和SOCKET API。以及DNS,PING等直接調用的函數。5)本協議可以完成客戶機,服務器,UDP客戶機,UDP服務器。還可以方便完成DNS
    發表于 09-03 15:03

    Modbus TCPModbus RTU的實現

    設施,而大批量的Modbus RTU設備已經存在。用一個統一的Modbus TCP客戶端軟件去訪問所有的Modbus設備,統一、集中式管理將
    發表于 08-10 10:04

    TCP通信時服務如何接收客戶端的數據?

    畢設采用的是TCP協議,組員做的是下位機,C編程,WiFi模塊工作處于客戶端。我負責上位機,Labview使用tcp協議時服務
    發表于 04-14 14:49

    如何使用Socket實現TCP客戶端

    本教程介紹了如何編寫一個基于 socket 編程實現TCP 客戶端。我們先將 socket 編程的流程列出來,然后給出具體的實例。
    發表于 03-30 07:07

    怎樣去設計嵌入式LWIP網絡客戶端

    嵌入式LWIP網絡客戶端設計教程本文引用地址: 嵌入式技術的興起使得傳統的基于PC機的互聯網技術優勢不再,嵌入式網絡客戶端與服務技術成為熱點,而該技術需要移植性高、占用資源小的協議
    發表于 08-06 06:46

    stm32f107vc lwip tcp客戶端

    模擬的服務器,實現簡單的數據收發,通過上位機控制板子的LED燈一 打開工程《科星F107開發板網絡應用篇之TCP客戶端》打開M
    發表于 08-06 09:17

    JAVA教程之TCP客戶端

    JAVA教程之TCP客戶端,很好的JAVA的資料,快來學習吧
    發表于 04-11 17:28 ?7次下載

    TCP回響客戶端:RAW API接口

    TCP回響客戶端例程(RAW API)
    的頭像 發表于 07-05 00:31 ?3907次閱讀
    <b class='flag-5'>TCP</b>回響<b class='flag-5'>客戶端</b>:RAW API接口

    基于LwIP的TCP客戶端設計

    上一篇我們基于LwIP協議的RAW API實現了一個TCP服務器的簡單應用,接下來一節我們來實現一個T
    的頭像 發表于 12-14 15:12 ?2239次閱讀
    基于LwIP的<b class='flag-5'>TCP</b><b class='flag-5'>客戶端</b>設計

    基于LwIP的HTTP客戶端設計

    前面我們實現TCP服務器和客戶端的簡單應用,接下來我們實現一個基于TCP協議的應用
    的頭像 發表于 12-14 15:19 ?2769次閱讀
    基于LwIP的HTTP<b class='flag-5'>客戶端</b>設計