iT邦幫忙

0

Modbus RTU簡介(上)

1 前言

1.1 什麼是Modbus

  • Modbus是一種用於工業控制的標準通信協議,它定義了裝置之間在應用層的消息封裝模式、溝通方法、溝通順序。
  • Modbus的優勢 :
    1. Modbus協議是開源免費的
    2. Modbus支援多種常見工控接口(RS232, RS485, TCP/IP etc.),且可以各種物理層裝置上傳輸(雙絞線、光纖、無線等)
    3. Modbus格式簡單易於開發
  • Modbus能夠將眾多設備連接到DCS, PLC系統上,再利用服務器(雲、中央計算機)進行監控與下達指令,以便於集中式控制。
    1-1 Modbus在工業上的應用

1.2 Modbus的通訊

  • Modbus通信協議是一個(master/slave)架構,或者(client/server)架構,在整個通訊網路中能夠同時擁有多個slaves但是只允許擁有一個專門發送request的master。
  • Modbus是一個一主多從協議(最多可連接247台slave,所以slave地址範圍在1~247之間),只有在master發出request時slave才會做出回應,slaves之間不能溝通。
  • 每條master所發出的request,都包含一個slave地址,每台slave都會收到該request,都只有符合該地址的slave才會回應該請求,如圖1-1(地址0是廣播模式,每台slave都會運行指令但不會回應master)。
1-2 Modbus的應答過程

  • ADU(Application Data Unit)是完整的協議傳輸封包而PDU(Protocol Data Unit)則是資料傳輸的基礎單元,與通信無關,如圖1-2所示。
1-3 通用Modbus封包格式

1.3 Modbus的錯誤通訊

當master傳送的request不符合格式、slave不支援此功能等問題時,代表slave不能正確解碼request內容,這時slave就會response一個error response,其組成為[slave ID][error code][exception code]

  • slave ID=original
  • error code=function code + 0x80
  • exception code=01, 02, 03, 04, etc(依照發生錯誤的原因)
  • CRC校正碼
1-4 error response

1-5 Table of exception codes

2 Modbus重點內容

2.1 Modbus暫存器

2.1.1 暫存器種類

Modbus其中一重要的概念是暫存器,不同地址的暫存器存放著不同數據類型型與讀寫特性得資料,而這裡所說的暫存器地址不一定是固定的內存地址,也可以是開發者自行定義的連續或不連續的一塊儲存區域。我們可以把Modbus暫存器分為如圖2-1所示的4大主要部分。

2-1 Modbus暫存器種類

2.1.2 暫存器地址分配

  • 這裡有關地址的概念容易混淆,我的理解是暫存器PLC地址是給"人"看的,想當然爾從1開始(使用10進位制),前綴的0、1、4、3只是用來代表功能碼而已,真正要注意的是後4碼地址。
  • 暫存器Modbus協議地址是給"機器"看的,所以使用16進位制處理,從0開始,然後再搭配1byte的功能碼處理。
2-2 暫存器地址分配

2.2 RTU封包格式

  • Modbus封包最大長度為256bytes
2-3 Modbus的問答

2.2.1 master request format

[從機地址] [功能碼] [暫存器地址] [暫存器數量(word數)] [驗證碼]

ex : [1F] [04] [00 0A] [00 04] [D2 75]

2.2.2 slave response format

[從機地址] [功能碼] [幾個bytes] [data] [驗證碼]

ex : [1F] [04] [08] [00 01 FF FF 00 00 00 00] [54 FE]

2.2.2 封包之間的區隔

Modbus封包之間的區隔是使用3.5個字符時間來判斷,在該時間區間內,master與slave不做任何動作,利用字符時間的機制只適用於Modbus RTU。

封包之間的時間間格在計算上其實還取決於鮑率,還有格式問題:

  • 依據Modbus國家規範,一個字符時間為處理11 bits資料所需時間,一般包含一個起始位、8個數據位、1個校驗位 、一個停止位,而不是所謂一個byte(8 bits)的時間,這裡不要搞混,這是官方規定

  • 所謂封包之間的間隔指的是在serial port上的所有封包,包含request、reaponse,只要有資料流淌,就必須規定他們之間的區分方法

  • 所以我們假設當前鮑率為9600,也就是9600 bits per second,而3.5個字符時間就等於3.5*11=38.5位,那麼我們可以求得該Modbus RTU要求封包之間的時間間格為 : (38.5*1000)/9600 = 4.0104167ms

  • 由於頻繁的計算會對CPU造成負擔,所以Modbus官方規定,當鮑率超過19200時,封包時間間格會固定為1.75ms

  • 另外一種較為簡易的設定是不管鮑率為何,統一設定成10ms的時間間格,好處是釋放cpu壓力、較為簡便,對於對時間要求沒有那麼即時的系統,壞處是效率較低、不夠精準

  • 另外Modbus還有一個字元之間的判斷,一樣是利用字符時間機制,假設一個數據中相鄰兩個字元的時間差在1.5個
    字符時間以上,就會判斷該筆資料丟失 (1.5*11*1000)/baud rate ms,當鮑率超過19200時,時間間格設定成定值0.75ms

2-4 Modbus RTU封包之間的間格機制

2.3 地址範圍

Modbus的ID號為1bytes(0~255),但是前面有提過,slave最多只能設定成247,這是因為0是廣播模式,而剩餘的248~255是Modbus的保留ID,供更高級開發用,所以實際應用上我們能設定的範圍在1~247之間。

2.4 功能碼

Modbus的功能碼主要對應四個大方向—DO, DI, AO, AI,其中的功能碼主要也是處理這四大方向(對應連接的slave提供的可能是溫度數據、濕度數據、是否上鎖等數位類比消息)。功能碼占總封包1個byte,不過允許範圍在1~127,0在上面有提到分配給廣播模式,而128~255之所以不分配主要原因為假如1~127發生錯誤加上0x80的錯誤碼後會變成讓上限變成255,所以若是開放128以後的數會讓功能碼區段超過1個bytes的範圍。

  • 另外Modbus也提供使用者65~72, 100~110的自訂義功能碼區段
2-5Modbus主要功能碼

2-6Modbus功能碼區段

2.4.1 讀取數位輸出狀態(DO)

  • 功能碼代號 : 01(0x)
  • 功能 : 該功能碼為讀取coil線圈數位輸出狀態資訊,若狀態為on則輸出1,反之若為off則輸出0
  • 佔用大小 : 若為n個bits,則佔用N=n/8個bits,若不能整除則N+1
  • 讀寫狀態 : R/W
  • 線圈地址上限 : 1~2000
  • Modbus起始地址 : 0x0000~0xffff

Request

請求部份我們首先填入功能碼01,再來需要注意的是起始地址為2個bytes,這裡填的Modbus的地址主要由使用者決定(0x0000~0xffff)分別為HI高位與LO低位,由線圈20~38(Dec)可得需請求19個線圈數據,但是我們實際讀取的是Modbus地址19~37(Dec)因此將首地址轉換成HEX為0x0013,數量地址也分成高低兩位共2個bytes,所以我們可以得到00Hi 13Lo。

請求封包佔8bytes長度。

Response

如果我們要讀取線圈20~38的狀態,需要先計算總共需要回傳38-20+1=19個bits,19/8=2...3,不能整除所以要多分配一個bytes(用來補足的bits都設定成0),可以得出回傳的data佔有3個bytes。假設線圈20~27的狀態分別為on-on-off-off-on-on-off-on,要注意我們需要從LSB開始存取狀態,因此Binary Status為 1100 1101轉換成HEX就是CD,以此類推我們可以得到圖2-7的資料封包的排序如下所示。

響應封包的資料長度視請求的暫存器數量而定,最長不超過256bytes,data最長2000/8=250bytes。

2-7 功能碼01的封包格式

2.4.2 讀取數位輸入狀態(DI)

  • 功能碼代號 : 02(1x)
  • 功能 : 該功能碼為讀取coil線圈數位輸入狀態資訊,若狀態為on則輸出1,反之若為off則輸出0
  • 佔用大小 : 若為n個bits,則佔用N=n/8個bits,若不能整除則N+1
  • 讀寫狀態 : R
  • 線圈地址上限 : 1~2000
  • Modbus起始地址 : 0x0000~0xffff

Request

請求部份我們首先填入功能碼02,再來需要注意的是起始地址為2個bytes,這裡填的Modbus的地址主要由使用者決定(0x0000~0xffff)分別為HI高位與LO低位,由線圈19~218(Dec)可得需請求22個線圈數據,但是我們實際讀取的是Modbus地址196~217(Dec)因此將首地址轉換成HEX為0x00C4,數量地址也分成高低兩位共2個bytes,所以我們可以得到00Hi C4Lo。

Response

如果我們要讀取線圈197~218的狀態,需要先計算總共需要回傳218-197+1=22個bits,22/8=2...6,不能整除所以要多分配一個bytes(用來補足的bits都設定成0),可以得出回傳的data佔有3個bytes。假設線圈197~204的狀態分別為off-off-on-on-off-on-off-on,要注意我們需要從LSB開始存取狀態,因此Binary Status為 1010 1100轉換成HEX就是CD,以此類推我們可以得到圖2-8的資料封包的排序如下所示。

2-8 功能碼02的封包格式

2.5.1 讀保持暫存器(AO)

  • 功能碼代號 : 03(4x)
  • 功能 : 該功能碼為讀寫暫存器類比輸出狀態資訊,其輸出以Word為基本單位(1Word=2bytes)
  • 佔用大小 : 若為n個Word,則佔用2*n個bytes
  • 讀寫狀態 : R/W
  • 暫存器地址上限 : 1~125
  • Modbus起始地址 : 0x0000~0xffff

Request

請求部份我們首先填入功能碼03,再來需要注意的是起始地址為2個bytes,這裡填的Modbus的地址主要由使用者決定(0x0000~0xffff)分別為HI高位與LO低位,由暫存器地址108~110(Dec)可得需請求3個暫存器數據,但是我們實際讀取的是Modbus地址107~109(Dec)因此將首地址轉換成HEX為0x006B,數量地址也分成高低兩位共2個bytes,所以我們可以得到00Hi 6BLo。

Response

如果我們要讀取暫存器108~110的狀態,需要先計算總共需要回傳110-108+1=3個Word,2*3=6個bytes,可以得出回傳的data佔有6個bytes。假設暫存器108的輸出為555(Dec),我們可以經過轉換得到0x022B,然後依高低位分別填入02Hi 2BLo,依此類推暫存器109、110輸出分別為0以及100,經過轉換分別得到00 00與00 64(HEX)。

另外假如回傳暫存器狀態設定成32bits,那麼暫存器取值就需要佔用到108、109兩個暫存器位置共4bytes,下一個暫存器將從110開始。

2-9 功能碼03的封包格式

2.5.2 讀輸入暫存器(AI)

  • 功能碼代號 : 04(3x)
  • 功能 : 該功能碼為讀取暫存器類比輸入狀態資訊,其輸出以Word為基本單位(1Word=2bytes)
  • 佔用大小 : 若為n個Word,則佔用2*n個bytes
  • 讀寫狀態 : R
  • 暫存器地址上限 : 1~125
  • Modbus起始地址 : 0x0000~0xffff

Request

請求部份我們首先填入功能碼04,再來需要注意的是起始地址為2個bytes,這裡填的Modbus的地址主要由使用者決定(0x0000~0xffff)分別為HI高位與LO低位,範例中我們要讀取暫存器9的數值,但是我們實際讀取的是Modbus地址08因此將首地址轉換成HEX為0x0008,數量地址也分成高低兩位共2個bytes,所以我們可以得到00Hi 08Lo。

Response

如果我們要讀取暫存器9的狀態,總計1個Word,共2個bytes,可以得出回傳的data佔有2個bytes。假設暫存器9的輸出為10(Dec),我們可以經過轉換得到0x000A,然後依高低位分別填入00Hi 0ALo。

另外假如回傳暫存器狀態設定成32bits,那麼暫存器取值就需要佔用4bytes,那麼取直就需要暫用暫存器9與10的位置。

2-10 功能碼04的封包格式


尚未有邦友留言

立即登入留言