91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

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

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

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

使用協(xié)議棧實現(xiàn)Modbus ASCII從站應用

CHANBAEK ? 來源:木南創(chuàng)智 ? 作者:尹家軍 ? 2022-12-13 17:12 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

1 、何為ASCII從站

我們知道Modbus協(xié)議是一個主從協(xié)議,所以就存在主站和從站之分。所謂ASCII從站,簡單來說就是被動響應主站請求的站點,所以我們可以說ASCII從站就是響應通訊的一方。

對于ASCII從站來說,它會生成數(shù)據(jù),但他不會主動向外發(fā)送數(shù)據(jù),只有當收到主站的數(shù)據(jù)請求后,從站才會根據(jù)主站的請求發(fā)送數(shù)據(jù)。這一過程如下圖所示:

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

雖然Modbus ASCII與Modbus RTU都是基于串行鏈路來實現(xiàn)的,但在數(shù)據(jù)傳輸?shù)膱笪母袷缴洗嬖谳^大區(qū)別。相比于Modbus RTU,Modbus ASCII采用ASCII碼的形式來發(fā)送報文,并且有確定的起始字符和結(jié)束字符。具體結(jié)構(gòu)如下:

在ASCII模式下,每個8位的字節(jié)被拆分成兩個ASCII字符進行發(fā)送。對于數(shù)據(jù)部分,根據(jù)具體發(fā)送的數(shù)據(jù)量來確定長度。校驗方式則采用的是LRC校驗方式。LRC校驗較為簡單,把每一個需要傳輸?shù)臄?shù)據(jù)字節(jié)迭加后取反加1即可。

2 、如何實現(xiàn)ASCII從站

我們已經(jīng)了解的從站總是響應主站的數(shù)據(jù)請求來實現(xiàn)數(shù)據(jù)的傳送。下面我們來看看使用協(xié)議棧如何實現(xiàn)一個從站。

我們知道從站是數(shù)據(jù)的生產(chǎn)者,對于Modbus協(xié)議來說有四類數(shù)據(jù):線圈、狀態(tài)、輸入寄存器和保持寄存器。所以在從站中我們要為這四種數(shù)據(jù)定義相應的地址,以便主站能夠?qū)脑L問。所以設計一個從站我們先來設計它的數(shù)據(jù)地址,在我們的例子中我們規(guī)定如下:

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

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

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

uint16_t ParsingAsciiMasterAccessCommand(uint8_t *receivedMessage,uint8_t *respondBytes, uint16_t rxLength, uint8_t StationAddress)

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

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

3 、 ASCII****從站編碼

我們已經(jīng)描述了使用協(xié)議棧實現(xiàn)Modbus ASCII從站的方法和流程,接下來我們就來利用協(xié)議棧具體實現(xiàn)一個Modbus ASCII從站的實例。

我們調(diào)用解析函數(shù)對接收到的數(shù)據(jù)請求進行解析,具體調(diào)用方式如下所示:

respondLength=ParsingAsciiMasterAccessCommand(asciiSlaveRxBuffer,respondBytes, asciiSlaveRxLength,StationAddress);

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

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

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

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

/*獲取想要讀取的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);
}

到這里對從站的開發(fā)實際已經(jīng)完成。對于這些回調(diào)函數(shù)并不是全部需要編寫,而是要根據(jù)我們自己定義的從站各類參數(shù)的地址分配來實現(xiàn)。

4 、 ASCII****從站小結(jié)

我們使用協(xié)議棧實現(xiàn)了一個簡單的Modbus ASCII從站應用。我們可以使用Modscan、Modbus poll以及各類串口通訊工具對其進行測試。在使用Modbus poll時將其數(shù)據(jù)格式設為ASCII即可。測試結(jié)果如下:

與Modbus RTU從站類似,Modbus ASCII從站的實現(xiàn)也較為簡單,因為在同一臺設備上只需實現(xiàn)一個從站,哪怕是通過不同的端口來訪問。這一點與主站是不一樣的,原因是從站的數(shù)據(jù)是自己產(chǎn)生,而且只需被動響應主站請求,而且理論上同一條總線只會有一個主站。

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

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

協(xié)議棧下載: https://github.com/foxclever/Modbus

示例下載: https://download.csdn.net/download/foxclever/12882021

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

    關(guān)注

    28

    文章

    2457

    瀏覽量

    83198
  • ASCII
    +關(guān)注

    關(guān)注

    5

    文章

    172

    瀏覽量

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

    關(guān)注

    2

    文章

    146

    瀏覽量

    34588
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    Modbus RTU的設計與實現(xiàn)

    前面我們已經(jīng)詳細講解過Modbus協(xié)議的開發(fā)過程,并且利用協(xié)議封裝了Modbus RTU主
    的頭像 發(fā)表于 12-13 15:27 ?2864次閱讀
    <b class='flag-5'>Modbus</b> RTU的設計與<b class='flag-5'>實現(xiàn)</b>

    使用協(xié)議實現(xiàn)Modbus RTU主應用

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

    使用協(xié)議實現(xiàn)Modbus RTU應用

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

    使用協(xié)議實現(xiàn)Modbus TCP客戶端應用

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

    【RA-Eco-RA6M4開發(fā)板評測】——6.原創(chuàng)0到1完整實現(xiàn)modbus master協(xié)議

    上一篇帖子中我已經(jīng)從無到有的完整實現(xiàn)modbus slave,這篇帖子就來0到1來實現(xiàn)
    發(fā)表于 07-25 20:22

    【RA4M2-SENSOR】—— 10.實現(xiàn)modbus協(xié)議

    modbus協(xié)議在工業(yè)控制領(lǐng)域有著廣泛的應用,很多機器人控制和PLC伺服控制器都是使用modbus協(xié)議來通信的。 本次測評就是使用我自己實現(xiàn)modbus slave
    發(fā)表于 09-01 07:06

    Modbus協(xié)議轉(zhuǎn)換芯片

    OD2122接口芯片OD2122是一款Modbus協(xié)議轉(zhuǎn)換芯片,支持基于RS485、RS232C總線的Modbus(RTU)
    發(fā)表于 12-26 09:43

    linux平臺實現(xiàn)modbus主機協(xié)議的動態(tài)庫libMbpoll

    libMbopll動態(tài)庫是面向linux平臺設計的modbus主機協(xié)議,可以運行在x86平臺以及各種嵌入式linux平臺;協(xié)議提供了簡單
    發(fā)表于 05-28 14:23

    linux平臺實現(xiàn)modbus主機協(xié)議的動態(tài)庫libMbpoll

    libMbopll動態(tài)庫是面向linux平臺設計的modbus主機協(xié)議,可以運行在x86平臺以及各種嵌入式linux平臺;協(xié)議提供了簡單
    發(fā)表于 05-28 14:55

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

    1、Agile Modbus介紹  Agile Modbus 即:輕量型 modbus 協(xié)議,滿足用戶任何場景下的使用需求?! xamp
    發(fā)表于 10-08 15:04

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

    版權(quán)要求,不用支付額外費用、硬件要求簡單容易部署、使用廣泛便于系統(tǒng)集成。Modbus采用半雙工的通訊方式,由1個子和多個組成,允許多個設備連接在同一個網(wǎng)絡上進行通訊。   2.
    發(fā)表于 05-05 16:19

    Modbus協(xié)議的理解

    和使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡進行通信的。標準的Modicon控制器使用RS232C實現(xiàn)串行的ModbusModbusASCII和RTU
    發(fā)表于 05-05 16:47

    MODBUS主/協(xié)議

    MODBUS主/協(xié)議:MODBUS協(xié)議是MODICOM公司1979年開發(fā)的一個為很多廠商支持的開放規(guī)約。它用來為各種智能設備建立相互通信
    發(fā)表于 09-20 18:09 ?131次下載

    使用協(xié)議實現(xiàn)Modbus ASCII應用

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

    EtherCAT轉(zhuǎn)Modbus網(wǎng)關(guān)做為MODBUS配置案例

    興達易控EtherCAT轉(zhuǎn)Modbus網(wǎng)關(guān)可以用作MODBUS的配置。這種網(wǎng)關(guān)允許將Modbus協(xié)議與EtherCAT
    的頭像 發(fā)表于 09-24 09:27 ?2088次閱讀
    EtherCAT轉(zhuǎn)<b class='flag-5'>Modbus</b>網(wǎng)關(guān)做為<b class='flag-5'>MODBUS</b><b class='flag-5'>從</b><b class='flag-5'>站</b>配置案例