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

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

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

3天內不再提示

使用協議棧實現Modbus RTU從站應用

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

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

1 、何為RTU從站

Modbus協議是一個主從協議,那肯定就有主站和從站之分。所謂從站就是被動動響應通訊的對象,所以從站總是響應通訊的一方。

對于RTU從站來說,它是數據的數據的生產者,從站通過響應主站數據請求的方式將數據發送給主站。這一過程如下圖所示:

從上圖我們不難看出,首先主站要主動發起數據請求,這也是它為什么被稱之為主站的緣由。它首先告訴從站我需要哪些數據。然后從站按照主站的請求返回數據。主站得到響應后解析數據,這樣就完成了主從站之間的一次數據通訊。所以主站就需要主動發起每一次數據通訊的對象。

2 、如何實現RTU從站

我們已經了解的從站總是響應主站的數據請求來實現數據的傳送。下面我們來看看使用協議棧如何實現一個從站。

我們知道從站是數據的生產者,對于Modbus協議來說有四類數據:線圈、狀態、輸入寄存器和保持寄存器。所以在從站中我們要為這四種數據定義相應的地址,以便主站能夠對應的訪問。所以設計一個從站我們先來設計它的數據地址,在我們的例子中我們規定如下:

我們規定了每類數據類型的數量為8,對于從站來說除了生成這些數據外,還需要根據主站的數據請求來返回相應的數據響應。在我們的協議棧中實現了0x01、0x02、0x03、0x04、0x05、0x06、0x0F以及0x10等功能碼。也就是說主站對象會生成面向這些功能碼的從站數據請求。從站收到請求后,解析請求并根據請求生成響應的數據響應。可以表示為下圖所示:

從上圖我們明白協議棧中已經實現了對收到的主站數據請求進行解析以及根據解析生成對應的響應的函數。我們使用協議棧時,主要需要做兩個方面的事情:解析數據請求和生成數據響應。

在協議棧中定義了一個解析函數,該函數將收到的數據請求消息解析,并根據解析的結果生成返回的數據響應。該函數的原型如下:

uint16_t ParsingMasterAccessCommand(uint8_t receivedMessage, uint8_trespondBytes, uint16_t rxLength, uint8_t StationAddress)

這個函數有四個參數:uint8_t receivedMessage是收到的數據請求消息; uint8_trespondBytes是返回的數據響應消息,也是函數需要生成的;uint16_t rxLength是接收到的數據請求消息的長度;uint8_t StationAddress本站的地址。而函數的返回值則是生成的數據響應詳細的長度。

在解析的過程中,該函數判斷消息的完整性,并根據不同的功能碼調用不同的回調函數來實現,包括設置本地數據和獲取本地數據的相關回調函數,在后續將討論它們的實現。

3 RTU****從站編碼

我們已經詳述了使用協議棧實現RTU從站的方法,接下來我們就來利用協議棧具體開發一個RTU從站的實例。

我們調用解析函數對接收到的數據請求進行解析,具體調用方式如下所示:

respondLength=ParsingMasterAccessCommand(hgudRxBuffer,respondBytes,hgudRxLength,StationAddress);

返回值會有3種情況,返回值為0則表示接收到的數據請求消息是錯誤的。返回值為65535則表示返回的消息尚未接收完整。返回的是一個合適的數值則表示解析成功,返回了數據響應的長度。

當然我們需要實現8個回調函數,分別是獲取線圈量、獲取狀態量、獲取輸入寄存器和獲取保持寄存器,以及預置單個線圈量、預置多個線圈量、預置單個保持寄存器和預置多個保持寄存器。函數原型定義如下:

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

我們需要做的工作就是根據我們具體實例中4類數據量的地址分配來實現這8個回調函數。當然,如果從站沒有某一類數據量操作,回調函數則不需要編寫。在我們的實例中我們將這幾個函數實現如下:

/*獲取想要讀取的Coil量的值*/
void GetCoilStatus(uint16_t startAddress,uint16_tquantity,bool *statusList)
{
  uint16_tstart;
  uint16_tcount;
  /*先判斷地址是否處于合法范圍*/
 start=(startAddress>CoilStartAddress)?((startAddress<=CoilEndAddress)?startAddress:CoilEndAddress):CoilStartAddress;
 count=((start+quantity-1)<=CoilEndAddress)?quantity:(CoilEndAddress-start);
 
  for(inti=0;i/*獲取想要讀取的保持寄存器的值*/
void GetHoldingRegister(uint16_tstartAddress,uint16_t quantity,uint16_t *registerValue)
{
  uint16_tstart;
  uint16_tcount;
  /*先判斷地址是否處于合法范圍*/
 start=(startAddress>HoldingResterStartAddress)?((startAddress<=HoldingResterEndAddress)?startAddress:HoldingResterEndAddress):HoldingResterStartAddress;
 count=((start+quantity-1)<=HoldingResterEndAddress)?quantity:(HoldingResterEndAddress-start);
 
  for(inti=0;i/*設置單個線圈的值*/
void SetSingleCoil(uint16_t coilAddress,boolcoilValue)
{
  /*先判斷地址是否處于合法范圍*/
 if((4<=coilAddress)&&(coilAddress<=CoilEndAddress))
  {
   dPara.coil[coilAddress]=coilValue;
  }
 
 PresetSlaveCoilControll(coilAddress,coilAddress);
}
 
/*設置多個線圈的值*/
void SetMultipleCoil(uint16_tstartAddress,uint16_t quantity,bool *statusValue)
{
  uint16_tendAddress=startAddress+quantity-1;
 if((4<=startAddress)&&(startAddress<=CoilEndAddress)&&(4<=endAddress)&&(endAddress<=CoilEndAddress))
  {
    for(inti=0;iPresetSlaveCoilControll(startAddress,endAddress);
}
 
/*設置單個寄存器的值*/
void SetSingleRegister(uint16_tregisterAddress,uint16_t registerValue)
{
  boolnoError=(bool)(((41<=registerAddress)&&(registerAddress<=42))
                     ||((44<=registerAddress)&&(registerAddress<=45))
                     ||((50<=registerAddress)&&(registerAddress<=51))
                     ||((54<=registerAddress)&&(registerAddress<=55))
                     ||((58<=registerAddress)&&(registerAddress<=59)));
 if(noError)
  {
   aPara.holdingRegister[registerAddress]=registerValue;
  }
 
 WriteSlaveRegisterControll(registerAddress,registerAddress);
}
 
/*設置多個寄存器的值*/
void SetMultipleRegister(uint16_tstartAddress,uint16_t quantity,uint16_t *registerValue)
{
  uint16_tendAddress=startAddress+quantity-1;
 
  boolnoError=(bool)(((8<=startAddress)&&(startAddress<=15)&&(8<=endAddress)&&(endAddress<=15))
                     ||((41<=startAddress)&&(startAddress<=42)&&(41<=endAddress)&&(endAddress<=42))
                     ||((44<=startAddress)&&(startAddress<=47)&&(44<=endAddress)&&(endAddress<=47))
                     ||((50<=startAddress)&&(startAddress<=51)&&(50<=endAddress)&&(endAddress<=51))
                     ||((54<=startAddress)&&(startAddress<=55)&&(54<=endAddress)&&(endAddress<=55))
                     ||((58<=startAddress)&&(startAddress<=59)&&(58<=endAddress)&&(endAddress<=59))
                     ||((62<=startAddress)&&(startAddress<=67)&&(62<=endAddress)&&(endAddress<=67))
                     ||((72<=startAddress)&&(startAddress<=77)&&(72<=endAddress)&&(endAddress<=77))
                     ||((82<=startAddress)&&(startAddress<=87)&&(82<=endAddress)&&(endAddress<=87))
                     ||((92<=startAddress)&&(startAddress<=97)&&(92<=endAddress)&&(endAddress<=97))
                     ||((100<=startAddress)&&(startAddress<=115)&&(100<=endAddress)&&(endAddress<=115)));
 if(noError)
  {
    for(inti=0;iWriteSlaveRegisterControll(startAddress,endAddress);
}

到這里對從站的開發實際已經完成。對于這些回調函數并不是全部需要編寫,而是要根據我們自己定義的從站各類參數的地址分配來實現。

4 RTU****從站小結

我們實現了一個簡單的RTU從站實例,我們可以通過一些RTU主站軟件來測試它。這樣的軟件有很多,常見的如Modscan、Modbus Poll等。這里我們使用Modbus Poll來測試一下,如下圖所示:

RTU從站的實現相對較簡單,因為在同一臺設備上只需實現一個從站,哪怕是通過不同的端口來訪問。這一點與主站是不一樣的,原因是從站的數據是自己產生,而且只需被動響應主站請求,而且理論上同一條總線只會有一個主站。

接下來我們來總結一下使用協議棧實現RTU從站的工作流程,或者說實現的步驟。首先從站要解析從主站送來的數據請求。在協議棧中已經封裝了數據請求的解析函數、所以我們實現從站時首先就是調用這一函數來解析接收到的數據請求消息。

然后將解析函數返回的數據響應消息發送到主站就可以了。也就是說使用協議棧,只需要調用一下這個函數從站功能就實現了。這是因為這個函數實現了整個從站的響應過程,大致分三個步驟:第一步,解析收到的主站數據請求消息;第二步,根據解析的結果預置數據或者獲取數據,預置和獲取數據由8個回調函數實現;第三步,生成從站數據響應消息。說到這里我們已經清楚,RTU從站必須實現這些回調函數,其它工作則全由協議棧完成。

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

    關注

    28

    文章

    1824

    瀏覽量

    77349
  • RTU
    RTU
    +關注

    關注

    0

    文章

    418

    瀏覽量

    28778
  • 協議棧
    +關注

    關注

    2

    文章

    144

    瀏覽量

    33710
收藏 人收藏

    評論

    相關推薦

    Modbus RTU的設計與實現

    前面我們已經詳細講解過Modbus協議的開發過程,并且利用協議封裝了Modbus RTU
    的頭像 發表于 12-13 15:27 ?2075次閱讀
    <b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>的設計與<b class='flag-5'>實現</b>

    使用協議實現Modbus RTU應用

    自從開源了我們自己開發的Modbus協議之后,有很多朋友建議我針對性的做幾個示例。所以我們就基于平時我們的應用整理了幾個簡單但可以說明基本的應用方法的示例,在這一篇中我們先來使用協議
    的頭像 發表于 12-13 16:10 ?1729次閱讀
    使用<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'>RTU</b>主<b class='flag-5'>站</b>應用

    使用協議實現Modbus ASCII應用

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

    EtherCATmodbus RTU協議轉換網關用modbus slave測試的方法

    使用,也可以連接到Modbus-RTU總線中作為主使用。這款通訊網關還支持多種不同的通訊協議,可以在不同的網絡中進行自由切換,極大的
    的頭像 發表于 10-24 19:22 ?1553次閱讀
    EtherCAT<b class='flag-5'>從</b><b class='flag-5'>站</b>轉<b class='flag-5'>modbus</b> <b class='flag-5'>RTU</b><b class='flag-5'>協議</b>轉換網關用<b class='flag-5'>modbus</b> slave測試的方法

    Modbus協議轉換芯片

    OD2122接口芯片OD2122是一款Modbus協議轉換芯片,支持基于RS485、RS232C總線的Modbus
    發表于 12-26 09:43

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

    整合起來監控管理,目前上位機大部分用的Modbus TCP協議,而現場設備有大批量使用的是Modbus RTU協議,要
    發表于 08-18 18:36

    基于RT-Thread實現的Agile Modbus協議

    基于 RT-Thread 實現的支持 Modbus 固件升級的 Bootloader:HPM6750_Boot  特性  支持 rtu 及 tcp 協議,使用純 C 開發,不涉及任何硬
    發表于 10-08 15:04

    基于Modbus RTU協議實現的1主多自組網無線通信形式

      本方案是基于Modbus RTU協議實現的1主多自組網無線通信形式,主為S7-1200
    發表于 03-10 14:54

    上位機MODBUS RTU通訊的VB程序

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

    S7200 Modbus通訊協議遠程終端設備RTU示例

    本文檔的主要內容詳細介紹的是S7200 Modbus通訊協議遠程終端設備RTU示例。
    發表于 10-25 08:00 ?33次下載
    S7200 <b class='flag-5'>Modbus</b>通訊<b class='flag-5'>協議</b>遠程終端設備<b class='flag-5'>RTU</b>主<b class='flag-5'>站</b>和<b class='flag-5'>從</b><b class='flag-5'>站</b>示例

    如何在S7-200 CPU上實現Modbus RTU通信協議

    S7-200 CPU上的通信口Port0可以支持Modbus RTU協議,成為Modbus RTU
    發表于 03-18 08:00 ?3次下載

    modbus rtu協議的主從源程序

    modbus rtu協議的主從源程序,移植到自己的串口即可用
    發表于 03-24 14:52 ?21次下載

    使用協議實現Modbus ASCII主應用

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

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

    遠創智控YC-CCLK-RTU型網關實現了CC-LinkModbus RTU
    的頭像 發表于 09-07 14:59 ?526次閱讀
    <b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>轉CC-Link<b class='flag-5'>協議</b>網關(CC-Link轉<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>)

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

    一,設備主要功能 捷米特JM-CCLK-RTU網關實現CC-LinkModbus RTU
    的頭像 發表于 09-10 10:28 ?719次閱讀
    <b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>轉CC-link<b class='flag-5'>協議</b>網關(<b class='flag-5'>Modbus</b> <b class='flag-5'>RTU</b>轉CC-link)
    主站蜘蛛池模板: 黄网站色成年片大免费软件 | 午夜性视频播放免费视频 | 天天天天色 | 亚洲成人在线免费观看 | 性欧美网站 | 亚洲一二三四 | 四虎精品成人免费观看 | 亚洲日韩色综合视频 | 丁香花五月婷婷开心 | 亚欧一区 | 免费观看一级成人毛片 | 一区二区免费看 | 看视频免费网址 | 日本三级日本三级人妇三级四 | 亚洲1区2区3区4区 | 九九99视频在线观看视频观看 | 最近最新视频中文字幕4 | 亚洲精品综合网在线8050影院 | 78m-78模成视频在线 | toyota东热综合网 | 超级乱淫片67194免费看 | 黄色三级视频网站 | 天天噜噜噜 | 成 人 黄 色视频免费播放 | 怡红院日本一道日本久久 | 色视频色露露永久免费观看 | 黄网免费| 天堂资源在线播放 | 亚洲视频一区二区在线观看 | 天天躁狠狠躁夜躁2021 | 久久这里只有精品免费播放 | 欧洲性开放大片免费观看视频 | 天堂在线最新版在线www | 色婷婷精品综合久久狠狠 | 永久视频免费 | 黄色拍拍拍 | 欧美视频综合 | 亚洲一区二区三区播放在线 | 亚洲一区二区影视 | 恐怖片大全恐怖片免费观看好看的恐怖片 | 国产亚洲人成网站天堂岛 |