Modbus協議相關


1:Modbus協議簡介

    Modbus協議主要描述的是應用層的信息封裝格式,處於OSI模式的第七層(應用層)。Modbus的物理層可以是RS-485、Ethernet II /802.3。Modbus協議棧的層次圖:
            

        本文主要介紹Modbus使用物理層是EIA/TIA-485的情況。Modbus主要內容爲應用層協議,所以在現實使用中可以將EIA/TIA-485(485)和Ethernet II /802.3(以太網)不同的物理連接網絡通過Modbus協議組成統一的系統。
使用EIA/TIA-485這種串行通訊方式的Modbus協議框圖:


物理層的EIA/TIA-485大家比較熟悉,現場總線通訊很多設備都使用485通訊。下面重點介紹一下Figure 2 中的 Data Link 層和Application層。
Application層主要目的是定義應用層的功能和參數。應用層幀格式見圖:

Modbus應用層的Function Code 就是我們熟悉的功能碼,常見的有04(read input register) 03(Read Holding Registers)等。這些內容大家比較熟悉,就不一一說明了。
具體功能碼含義可參見文章最後的相關資料及工具。

Data Link 層主要目的是確定總線上的具體從機以及檢驗數據幀傳輸是否正確。Data Link層的數據幀格式見圖:

其中Address field域是地址域,現場使用485總線,總線上可能存在很多設備,這個地址主要用於從總線上選擇一個具體的設備。CRC (or LRC是檢驗位)用於檢驗數據,確保傳輸正確。
在485總線上使用Modbus協議,有兩種主要方式:RTU ASCII。RTU傳輸方式傳輸的數據幀爲二進制數據,ASCII傳輸方式傳輸的是ASCII碼。舉例來說要發送 0x31(十進制數)使用RTU直接發送0x31就可以(佔用一個byte),而ASCII碼傳輸方式則需要發送0x33和0x31這兩個字節(即十六進制數0x31的 高低位分別佔用一個byte)。
兩種傳輸方式各有利弊,使用RTU傳輸效率高,使用ACSII可讀性好。
Modbus協議是一種主從式協議,即主站發起通訊,從站響應這種模式。
 最後,給大家一個看一個完整的Modbus協議幀格式:

關於Modbus的具體協議規定和Modbus在串行傳輸(485)中的使用,請大家查看4:相關資料及工具 裏的

Modbus_Application_Protocol_V1_1b3.pdf
Modbus_over_serial_line_V1_02.pdf

其他Modbus相關資料請參考網站:http://www.modbus.org/

2:FreeMODBUS移植

    FreeMODBUS是一個開源的MODBUS協議棧,使用ANSI C語言編寫,可在常見的處理器上移植(不需要嵌入式操作系統的支持,當然可以通過很簡單的修改可以在嵌入式操作系統上運行)。FreeMODBUS支持從機,若想使用FreeMODBUS實現主機MODBUS,則需要根據實際需求進行二次開發MODBUS協議棧。
關於Modbus的軟件結構,移植,配置,使用網上有很多資料和移植經驗。我就不詳細探討移植和FreeMODBUS的軟件結構。這裏只是簡單說一下軟件的大致結構以及移植過程中需要注意的地方。我會根據MODBUS協議棧的協議規定,以FreeMODBUS爲原型,說明從協議棧的規定到具體實現之間的關係。另外,也談一下自己對通訊協議的一些個人想法。
前面說過,MODUBS串行口傳輸方式中存在RTU、ASCII 兩種方式。這裏只針對RTU方式進行分析,ASCII方式自行分析。
 FreeMODBUS的整體軟件結構是:前後臺系統。利用串行口接收、發送中斷完成數據幀在物理層的傳輸:接收時,接到一幀完整無誤的數據幀就通過事件的方式通知前臺程序,前臺程序根據收到的數據幀做相應的處理。發送時,先封裝應用層數據內容,然後再封裝鏈路層數據,最後通過串口中斷的方式發送出去。
通過分析FreeMODBUS的整體軟件結構我們很容易就知道,FreeMODBUS需要使用到串口(RS485),我們移植FreeMODBUS要實現初始化串口、讀寫串口、初始化並控制串口中斷。
接下來一個重要的問題是RTU方式的MODBUS如何判別一幀數據包哪?有的協議裏有開始標示、結束標示,通過判別開頭標示和結束標示來表示一幀完整的數據幀。但根據前面的介紹,我們發現MODBUS RTU方式的數據幀並沒有開始標示和結束標示,那MODBUS RTU怎麼判別一幀數據幀的哪?我們還要看MDBUS協議棧的具體規定。先給大家看一個圖:

MODBUS協議裏面說一幀數據和下一幀數據之間的間隔至少是3.5個字符。按照9600的波特率來算的話(9600 N 1,一幀數據爲10bit),1S大約能傳輸960字節,一個字符(1 Byte)的傳輸時間大約爲1ms多點。那這個T3.5應該在4ms左右。也就是說一幀完整的數據幀和下一個數據幀之間的間隔應>=4ms。也就是圖示中的 Start >= 3.5Char 、End >= 3.5 Char。
MODBUS RTU方式 還有一個時間要求:

根據圖示,很明顯MIDBUS協議要求一幀數據裏,byte和byte之間的時間間隔應<= 1.5個字符,如果還是按照9600的波特率來計算的話,大約是1.56ms。一幀數據內超出這個數值認爲數據包錯誤。

我們知道了這個,似乎明白了MODBUS協議棧是使用兩個時間來確定一幀完整的數據包的。記住哦,T3.5 T1.5 很重要的MODBUS協議參數。然後我們也很容易想到FreeMODBUS要實現精確延時,有可能會使用到定時器,對了,你沒猜錯,FreeMODBUS除了佔用一個串口硬件資源外,它還佔用了一個定時器硬件資源。所以移植的時候也要處理定時器有關的初始化、啓動定時、關閉定時、開關定時器中斷等操作。
下面,我們來說一下FreeMODBUS是如何實現上述時間要求的。根據我看FreeMODBUS的源代碼,它只利用了一個T3.5,並沒有實現T1.5這個時間要求。我的理解是這樣的:
FreeMODBUS一般作爲從機,從機作爲接收時,若主發送的數據不滿足T1.5的要求,FreeMODBUS並沒有檢測,FreeMODBUS只檢測是否滿足T3.5這個時間,若byte和byte之間的間隔>=T3.5 這個時間,則認爲一幀數據包接收完畢。它的設計可能是假定了主機發送的數據幀格式完全符合MODBUS協議。
而從機發送數據時,是使用串口中斷髮送,肯定滿足T1.5的要求,因爲MODBUS是主從模式,主機發送完命令,從機接收到後纔給主機響應,這種通訊業肯定能滿足T3.5這個要求。
好了,我們現在看看FreeMODBUS是怎麼實現接收數據幀時根據這個T3.5來實現判斷接收完一幀完整的數據幀的。大致流程是這樣,初始化一個4ms的定時器,並打開定時器中斷,在每次接收到1個byte時,都重置定時器計數值並啓動定時器,然後若時間都過去4ms了都沒有收到新的byte,那麼就認爲一幀數據接收完畢。這個也很好理解吧,可以好好琢磨一下這個實現方案。

最後,還有一個事件處理需要在移植FreeMODBUS的時候考慮,這個簡單,其實就是在接受完一幀數據或者出錯後,通知前臺的查詢程序,讓它做相應的處理。

FreeMODBUS大致分了3層,底層的接收、發送策略(符合MODBUS協議規定)。中間MODBUS協議。然後就是上層應用層,每層的接口設計的不錯,方便移植,應用層也方便擴展。


 FreeMODBUS 的官方網站:www.freemodbus.org

3:PLCmodbus 地址

            MODBUS協議及FreeMODBUS的基本工作原理、移植都介紹完了。我們接下來看看MODBUS實際應用時的地址一般是怎麼定義的。
先說一下標準MODBUS協議裏的地址和設備定義的地址之間的關係。見下圖:

也就是說,一般設備定義的應用層地址是MODBUS協議裏地址數值+1。這麼說可能不太容易理解,我舉個例子吧,我們做了一個設備支持MODBUS協議,我們給用戶的使用說明書裏說 0x0001這個地址是一個模擬輸入量(比如說是壓力),根據上面的MODBUS要求,我們發送的MODBUS協議裏的地址域裏應該填寫的內容是0x0001 - 0x0001 = 0x0000。即封裝成標準MODBUS協議幀時的地址是0。其實,這裏的Application specific 是指具體應用時的地址。這個地址只和具體使用一個設備時有關,這個地址和MODBUS協議裏的地址域裏的地址關係見上圖。

MODBUS使用最多的是PLC,我們就說說這個MODBUS通訊協議裏規定的地址和PLC定義的應用層地址之間是個什麼關係?

通常PLC 定義的  Modbus 地址由 5 位數字組成,包括起始的數據類型代號,以及後面的偏移地址。Modbus Master 協議庫把標準的 Modbus 地址映射爲所謂 Modbus 功能號,讀寫從站的數據。Modbus Master 協議庫支持如下地址: 
00001 - 09999:數字量輸出( 線圈)          
10001 - 19999:數字量輸入(觸點) 
30001 - 39999:輸入數據寄存器(通常爲模擬量輸入)
40001 - 49999:數據保持寄存器

也就是說,PLC編程時只需要設置讀取、寫入,還有5位PLC MODBUS地址即可,Modbus Master 協議庫會根據你填寫的地址內容自動轉換爲相應的標準MODBUS協議包內容,主要是根據5位地址中的第一位和設置的讀取還是寫入來生成MODBUS協議裏的功能碼和地址。

這裏不好理解,我還是舉例。比如有這樣一個系統需求:PLC採集壓力數據,根據壓力數據用來控制電機。PLC作爲主機,壓力採集器作爲從機,他們之間通過MODBUS協議通訊。壓力採集器支持標準的modbus協議。
我們想通過PLC讀取一路壓力數據。我們在PLC端編程時,設置成   讀取  地址寫成 30001(十進制數)。其實通過Modbus Master 協議庫會把這樣的一個請求命令轉換爲標準的MODBUS協議。
具體爲:根據30001這個數據我們知道這個是一個輸入數據寄存器(通常爲模擬量輸入),在modbus協議棧裏這個對應的是 Input Register ,而我們是讀取。所以這個功能是Read Input Register (對應的標準MODBUS協議的功能碼是0x04) ,而地址我們先去掉最高位的3,剩下0001(十進制),然後根據MODBUS協議規定,我們應該再減去1,生成標準MODBUS協議。即地址爲0。轉換完後是這樣的一個結果,功能碼是0x04(1 byte),地址是0x0000(2 byte)


4:相關資料及工具

           
     Modbus_Application_Protocol_V1_1b3.pdf
   Modbus_over_serial_line_V1_02.pdf
        freeModbus代碼解讀及移植筆記.doc
        ModBus協議--易理解.doc
        ModbusPOLL工具

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章