Modbus学习总结
一、介紹
Modbus 協議是應用于電子控制器上的一種通用語言。通過此協議,控制器相互之間、控制器經由網絡(例如以太網)和其它設備之間可以通信。Modbus協議定義了一個控制器能認識使用的消息結構,而不管它們是經過何種網絡進行通信的。它描述了一控制器請求訪問其它設備的過程,如果回應來自其它設備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內容的公共格式。
Modbus 是一個請求/應答協議。也叫做Slave和Master與Server和Client。
同一種設備在不同領域的不同叫法。
Slave:工業自動化用語;響應請求;
Master:工業自動化用語;發送請求;
Server:IT用語;響應請求;
Client:IT用語;發送請求;
在Modbus中,Slave和Server意思相同,Master和Client意思相同。
?
modbus結構示意圖
二、協議分類
ModBus協議是應用層報文傳輸協議(OSI模型第7層),它定義了一個與通信層無關的協議數據單元(PDU),即PDU=功能碼+數據域。 ????
ModBus協議能夠應用在不同類型的總線或網絡。對應不同的總線或網絡,Modbus協議引入一些附加域映射成應用數據單元(ADU),即ADU=附加域+PDU。目前,
Modbus有下列三種通信方式:?
?1.以太網,對應的通信模式是MODBUS TCP。?
?2.異步串行傳輸(各種介質如有線RS-232-/422/485/;光纖、無線等),對應的通信模式是MODBUS RTU或MODBUS ASCII。 ????
?3.高速令牌傳遞網絡,對應的通信模式是Modbus PLUS。
?
ASCII模式
:
地址
功能代碼
數據數量
數據1
...
數據n
LRC高4位字節值
LRC低4位字節值?? ?
回車
換行
RTU模式
地址
功能代碼
數據數量
數據1
...
數據n
CRC高字節
CRC低字節
所選的ASCII或RTU方式僅適用于標準的Modbus網絡,它定義了在這些網絡上連續傳輸的消息段的每一位,以及決定怎樣將信息打包成消息域和如何解碼。“數據數量”字段只有在響應包中才有。
?
三、Modbus消息幀
兩種傳輸模式中(ASCII或RTU),傳輸設備以將Modbus消息轉為有起點和終點的幀,這就允許接收的設備在消息起始處開始工作,讀地址分配信息,判斷哪一個設備被選中(廣播方式則傳給所有設備),判知何時信息已完成。部分的消息也能偵測到并且錯誤能設置為返回結果。
1、ASCII幀
使用ASCII模式,消息以冒號(:)字符(ASCII碼 3AH)開始,以回車換行符結束(ASCII碼 0DH,0AH)。
其它域可以使用的傳輸字符是十六進制的0...9,A...F。網絡上的設備不斷偵測“:”字符,當有一個冒號接收到時,每個設備都解碼下個域(地址域)來判斷是否發給自己的。
?
消息中字符間發送的時間間隔最長不能超過1秒,否則接收的設備將認為傳輸錯誤。一個典型消息幀如下所示:
起始位
設備地址
功能代碼
數據
LRC校驗
結束符
1個字符
2個字符
2個字符
n個字符
2個字符
2個字符
2、RTU幀
使用RTU模式,消息發送至少要以3.5個字符時間的停頓間隔開始。在網絡波特率下多樣的字符時間,這是最容易實現的(如下圖的T1-T2-T3-T4所示)。傳輸的第一個域是設備地址。可以使用的傳輸字符是十六進制的0...9,A...F。網絡設備不斷偵測網絡總線,包括停頓間隔時間內。當第一個域(地址域)接收到,每個設備都進行解碼以判斷是否發往自己的。在最后一個傳輸字符之后,一個至少3.5個字符時間的停頓標定了消息的結束。一個新的消息可在此停頓后開始。
?
整個消息幀必須作為一連續的流轉輸。如果在幀完成之前有超過1.5個字符時間的停頓時間,接收設備將刷新不完整的消息并假定下一字節是一個新消息的地址域。同樣地,如果一個新消息在小于3.5個字符時間內接著前個消息開始,接收的設備將認為它是前一消息的延續。這將導致一個錯誤,因為在最后的CRC域的值不可能是正確的。一典型的消息幀如下所示:
起始位
設備地址
功能代碼
數據
CRC校驗
結束符
T1-T2-T3-T4
8Bit
8Bit
n個8Bit
16Bit
T1-T2-T3-T4
?
消息幀的地址域包含兩個字符(ASCII)或8Bit(RTU)。可能的從設備地址是0...247 (十進制)。單個設備的地址范圍是1...247。主設備通過將要聯絡的從設備的地址放入消息中的地址域來選通從設備。當從設備發送回應消息時,它把自己的地址放入回應的地址域中,以便主設備知道是哪一個設備作出回應。地址0是用作廣播地址,以使所有的從設備都能認識。當Modbus協議用于更高水準的網絡,廣播可能不允許或以其它方式代替。
應答包中,數據包括了數據字節長度+數據值,請求包中數據只包含數據值。
?Modbus TCP/IP數據幀結構
Modbus TCP/IP數據幀除了TCP已經有的包頭外,還有modbus TCP協議數據單元(ADU),包括MBAP幀頭以及與RTU數據內容相同的應用數據單元(PDU),地址碼除外。
???????其中與單純的TCP/IP或是modbus-RTU相比,多的內容就是一個MBAP報文頭:
MBAP報文頭定義
???????可以看出來,MBAP報文頭主要添加了以下附加信息,為了識別是請求還是響應而設置的事務元標識符(2個字節,通常為0,客戶端發出的檢驗信息,服務器端只是需要將這兩個字節的內容復制以后再放到回復報文的相應位置就可以)、為了判斷協議類型設置的協議標識符(2個字節,0=MODBUS協議)、為了區分可變長度數據幀結束的數據幀長度(從下一個字節起至結束的長度,2個字節)、還有用于標識從站地址的單元標識符(1個字節,即從站地址),與RTU不同的是,從站地址放在了MBAP幀頭里。這個里面的2個字節默認都是大端對齊(高字節、低字節)。
PDU單元與MODBUS RTU數據內容基本相同,由于有TCP/IP和鏈路層(以太網)校驗和機制所以去掉了CRC校驗碼,從站地址也放在了MBAP幀頭里。
另外Modbus TCP/IP默認端口為502。?
例子:
Modbus 控制命令為:
00 01 00 00 00 09 04 ????10 00 00 00 01 02 00 01
???????MBAP ???????????????????????????????PDU
上述命令可簡單的解釋為:00 01(事務標識符)00 00(協議標識符)00 09(后續字節數)04(設備標識符,即從站地址)10(功能碼,寫多個保持寄存器值)00 00(第一個地址,即地址 1)00 01(寫寄存器的個數,1個)02(后續所寫數據的長度)00 01(具體寫的數據)。
Modbus RTU與Modbus TCP讀指令對比
??? ?
MBAP報文頭
地址碼
功能碼
寄存器地址
寄存器數量
CRC校驗
Modbus RTU?? ?
無
01
03
01 8E
00 04
25 DE
Modbus TCP?? ?
00 00 00 00 00 06 00
無
03
01 8E
00 04
無
指令的涵義:從地址碼為01(TCP協議單元標志為00)的模塊0x18E(01 8E)寄存器地址開始讀(03)四個(00 04)寄存器。
Modbus RTU與Modbus TCP寫指令對比
??? ?
MBAP報文頭
地址碼
功能碼
寄存器地址
寄存器數量
數據長度
正文
CRC校驗
RTU?? ?
無
01
10
01 8E
00 01
02
00 00
A8 7E
TCP?? ?
00 00 00 00 00 09 00
無
10
01 8E
00 01
02
00 00
無
指令的涵義:從地址碼為01(TCP協議單元標志為00)的模塊0x18E(01 8E)寄存器地址開始寫(10)一個(00 01)寄存器,具體數據長度為2個字節(02),數據正文內容為00 00(00 00)。
MODBUS ASCII和RTU兩種模式的區別、優缺點
MODBUS ASCII協議和RTU協議的比較:?
協議?? ?開始標記?? ?結束標記?? ?校驗?? ?傳輸效率?? ?程序處理
ASCII?? ?:(冒號)?? ?CR,LF?? ?LRC?? ?低?? ?直觀,簡單,易調試
RTU?? ?無?? ?無?? ?CRC?? ?高?? ?稍復雜
MODBUS的ASCII協議和RTU協議相比,MODBUS ASCII協議擁有開始和結束標記,而MODBUS RTU卻沒有,所以ASCII協議的程序中對數據包的處理能更加方便。MODBUS ASCII協議的DATA域傳輸的都是可見的ASCII字符,因此在調試階段就顯得更加直觀,另外它的LRC校驗程序也比較容易編寫,這些都是MODBUS ASCII的優點。MODBUS ASCII的主要缺點是傳輸效率低,因為它傳輸的都是可見的ASCII字符,原來用RTU傳輸的數據每一個字節,用ASCII的話都要把這個字節拆分兩個字節,比如RTU傳輸一個十六進制數0xF9,ASCII就需要傳輸字符'F'和字符'9',對應的ASCII碼0x46和0x39兩個字節,這樣它的傳輸的效率肯定就比RTU低。所以一般來說,如果所需要傳輸的數據量較小可以考慮使用ASCII協議,如果所需傳輸的數據量比較大,最好能使用RTU協議。
另外,由于ASCII協議有開始標志和結束標志,所以一個數據包之間的各字節間的傳輸間隔時間可以大于1秒,而MODBUS RTU方式下,由于沒有規定開始和結束標記,所以協議規定每兩個字節之間發送或者接收的時間間隔不能超過3.5倍字符傳輸時間。如果兩個字符時間間隔超過了3.5倍的字符傳輸時間,就認為一幀數據已經接收,新的一幀數據傳輸開始,所以RTU方式下兩個字節間傳輸間隔有時間要求。MODBUS 的ASCII和RTU兩種協議的這一區別可能決定某些應用場合只能選用其中一種協議。
四、modbus功能碼
下表列出MODBUS支持的部分功能代碼:以十進制表示。
表1.1 MODBUS部分功能碼
代碼
中文名稱
寄存器PLC地址
位操作/字操作
操作數量
01
讀線圈狀態
00001-09999
位操作
單個或多個
02
讀離散輸入狀態
10001-19999
位操作
單個或多個
03
讀保持寄存器
40001-49999
字操作
單個或多個
04
讀輸入寄存器
30001-39999
字操作
單個或多個
05
寫單個線圈
00001-09999
位操作
單個
06
寫單個保持寄存器
40001-49999
字操作
單個
15
寫多個線圈
00001-09999
位操作
多個
16
寫多個保持寄存器
40001-49999
字操作
多個
modbus協議的數據主要分為四類:離散量輸入、線圈狀態、輸入寄存器、保持寄存器。離散量輸入對應開入(遙信),線圈狀態對應哪開出(遙控),輸入寄存器對應只讀的模擬量(遙測),保持寄存器對應可讀可寫的模擬量(遙調)。
1.1功能碼說明
????功能碼可以分為位操作和字操作兩類。位操作的最小單位為BIT,字操作的最小單位為兩個字節。
????????【位操作指令】 ???讀線圈狀態01H,讀(離散)輸入狀態02H,寫單個線圈06H和寫多個線圈0FH。
????????【字操作指令】 ???讀保持寄存器03H,寫單個寄存器06H,寫多個保持寄存器10H。
1.2Modbus數據模型
Modbus中,數據可以分為兩大類,分別為Coil和Register,每一種數據,根據讀寫方式的不同,又可細分為兩種(只讀,讀寫)。
Modbus四種數據類型:
數據名稱
數據含義
讀寫狀態
Discretes Input
位變量
只讀
Coils
位變量
?讀寫
Input Registers
16-bit類型
只讀
Holding Registers
16-bit類型
讀寫
?
1.3寄存器地址分配
表1.3 MODBUS寄存器地址分配
寄存器PLC地址
寄存器協議地址
適用功能
寄存器種類
讀寫狀態
描述
00001-09999
0000H-FFFFH
01H 05H 0FH
線圈狀態
可讀可寫
?
10001-19999
0000H-FFFFH
02H
離散輸入狀態
可讀
?
30001-39999
0000H-FFFFH
04H
輸入寄存器
可讀
每個寄存器表示一個16-bit無符號整數(0~65535)
40001-49999
0000H-FFFFH
03H 06H 0FH
保持寄存器
可讀可寫
兩個連續16-bit寄存器表示一個浮點數
50001-59999
0000H-FFFFH
03H 04H 06H 0FH
ASCII字符
可讀可寫
每個寄存器表示兩個ASCII字符
?
1.4寄存器種類說明
表1.4 MODBUS寄存器種類說明
寄存器種類
說明
PLC類比
舉例說明
線圈
狀態
輸出端口。可設定端口的輸出狀態,也可以讀取該位的輸出狀態。可分為兩種不同的執行狀態,例如保持型或邊沿觸發型。
DO
數字量輸出
電磁閥輸出,MOSFET輸出,LED顯示等。
離散
輸入狀態
輸入端口。通過外部設定改變輸入狀態,可讀但不可寫。
DI
數字量輸入
撥碼開關,接近開關等。
保持
寄存器
輸出參數或保持參數,控制器運行時被設定的某些參數。可讀可寫。
AO
模擬量輸出
模擬量輸出設定值,PID運行參數,變量閥輸出大小,傳感器報警上限下限。
輸入
寄存器
輸入參數。控制器運行時從外部設備獲得的參數。可讀但不可寫。
AI
模擬量輸入
模擬量輸入
?
1.5 PLC地址和協議地址區別
????PLC地址可以理解為協議地址的變種,在觸摸屏和PLC編程中應用較為廣泛。
1.5.1寄存器PLC地址
????寄存器PLC地址指存放于控制器中的地址,這些控制器可以是PLC,也可以使觸摸屏,或是文本顯示器。PLC地址一般采用10進制描述,共有5位,其中第一位代碼寄存器類型。第一位數字和寄存器類型的對應關系如表1所示。PLC地址例如40001、30002等。
1.5.2寄存器協議地址
????寄存器協議地址指指通信時使用的寄存器地址,例如PLC地址40001對應尋址地址0x0000,40002對應尋址地址0x0001,寄存器尋址地址一般使用16進制描述。再如,PLC寄存器地址40003對應協議地址0002,PLC寄存器地址30003對應協議地址0002,雖然兩個PLC寄存器寄存器通信時使用相同的地址,但是需要使用不同的命令訪問,所以訪問時不存在沖突。
?
五、注意事項
1、MODBUS 3.5T是如何計算的?
T = 1000毫秒*(1起始位+數據位+奇偶校驗+停止位)/波特率
如果你的通訊方式是:波特率115200(表示每秒傳輸多少字符),數據位8,無奇偶校驗。那么你發送一個字符的時間是:T=1000* (1起始位+8數據位+0奇偶校驗+1停止位)/ 115200=0.087ms。
發送端:發送一幀后延時7*T(其中3.5T是停止時間,3.5T是起始時間)再發送第二幀,保證一幀數據里頭各字節間間隔延時不能超過1.5T。
接收端:接收一個字節,查詢2T時間,是否有接收到下一個字節,有則這幀數據未完,繼續循環接收;沒有則默認這幀已經接收完畢。
2、串口超時時間設置
COMMTIMEOUTS timeout;
//填充timeout結構
GetCommTimeouts(m_h232Port,&timeout);
timeout.ReadIntervalTimeout=100;//兩字符之間最大的延時
timeout.ReadTotalTimeoutConstant=500;
timeout.ReadTotalTimeoutMultiplier=0;//讀取每字符間的超時
timeout.WriteTotalTimeoutConstant=2000;
timeout.WriteTotalTimeoutMultiplier=60;//寫入每字符間的超時
BOOLerror=SetCommTimeouts(m_hPort,&timeout);
ReadIntervalTimeout:兩字符之間最大的延時,當讀取串口數據時,一旦兩個字符傳輸的時間差超過該時間,讀取函數將返回現有的數據。設置為0表示該參數不起作用。?
ReadTotalTimeoutMultiplier:讀取每字符間的超時。?
ReadTotalTimeoutConstant:一次讀取串口數據的固定超時。所以在一次讀取串口的操作中,其超時為ReadTotalTimeoutMultiplier乘以讀取的字節數再加上 ReadTotalTimeoutConstant。將ReadIntervalTimeout設置為MAXDWORD,并將ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant設置為0,表示讀取操作將立即返回存放在輸入緩沖區的字符。?
WriteTotalTimeoutMultiplier:寫入每字符間的超時。?
WriteTotalTimeoutConstant:一次寫入串口數據的固定超時。所以在一次寫入串口的操作中,其超時為WriteTotalTimeoutMultiplier乘以寫入的字節數再加上 WriteTotalTimeoutConstant。?
3、在程序中如果要用到多個串口,而且還要做很多復雜的處理,那么最好不用MSComm通訊控件,網絡上有很多封裝好的串口類。
C++ class for Win32 serial ports:http://www.naughter.com/serialport.html
CSerialPort:https://github.com/itas109/CSerialPort
4、如何寫穩定的modbus代碼?
需要從穩定性和易讀性來考慮,如果穩定性較差會造成系統控制故障,如果易讀性差就會造成難以維護,這些控制指令之間差別很小,如果一個一個單獨寫命令,非常容易出錯。對應舉措如下:
1)避免每個指令寫一部分代碼,需要統一處理,比如校驗函數,發送函數,接收函數等。
通信協議已知,從中可以知道通信的實際數據長度(不包含包頭包尾和校驗的部分),所以可以控制讀寫多少個字節,并且可以知道什么時候啟動校驗,那些數據參與校驗計算。
2)為指令建立指令列表,這樣后來需要添加功能,就可以直接把指令字加入列表即可。
3)適當抽象。為每個指令的動作寫回調函數,這樣就可以在應用層,用一句簡單的回調函數指針直接操作具體的動作函數,而不是應用邏輯層操作具體的驅動層面的接口。
4)超時,必須有超時機制。通信失敗怎么處理?通信之后一般線斷了怎么處理?不能讓系統死等后面的幾個字節發過來。
5)接收超時機制,不能依靠數傳輸的字節個數來停止接收來和區分幀間隔,因為可能通信就是斷掉了,所以要按照協議,串口通信情況下3~5個T空閑就認為一幀結束。也可以通過協議事先計算出接收數據的總時間(字符數*(字符時間+字符間間隔時間)),使用該使用作為等待超時時間,但最長超時時間不能超過5T時間。
6)響應超時機制,Modbus是請求/應答式通信,那么主機就需要知道到底多久從機才會應答,主機等待從機應答的最長時間就是從機的最大回復間隔,超過這個時間后從機即使已經完成計算也不能回復,因為此時主機可能已經開始給其他從機發送數據了。
7)如果通信都是由你發起的,那么無論此次通信是完成還是超時或失敗,都應該關閉通信端口。
8)如果是線程中操作串口,可以提升線程優先級,讓操作系統在一定程度上提高串口讀寫性能。
9)ModbusRTU設備參數設置如下:
(1)內部屬性:單擊“查看設備內部屬性” ,點擊按鈕進入內部屬性
(2)最小采集周期:組態軟件對設備進行操作的時間周期, 單位為 ms, 默認為100ms,根據采集數據量的大小,設置值可適當調整
(3)設備地址:必須和實際設備的地址相一致,范圍為0-255,默認值為 0。
(4)通訊等待時間:通訊數據接收等待時間,默認設置為 200ms,根據采集數據量的大小,設置值可適當調整。
(5)快速采集次數:對選擇了快速采集的通道進行快采的頻率(已不使用,為與老驅動兼容,故保留,無需設置) 。
(6)16位整數解碼順序:調整字元件的解碼順序,對于Modicon PLC 及標準 PLC設備,使用默認值即可。
16 位整數解碼順序 舉例:0x0001
0―12 表示字元件高低字節不顛倒(默認值) 表示 1
1―21 表示字元件高低字節顛倒 表示 256
(7)32位整數解碼順序:調整雙字元件的解碼順序,對于Modicon PLC,請設置為“2-3412”順序解碼。
32 位整數解碼順序 舉例: 0x0000 0001
0―1234 表示雙字元件不做處理直接解碼(默認值) 表示 1
1―2143 表示雙字元件高低字不顛倒,但字內高低字節顛倒 表示256
2—3412表示雙字元件高低字顛倒,但字內高低字節不顛倒??表示65536
3—4321表示雙字元件內4個字節全部顛倒 表示 16777216
(8)32位浮點數解碼順序:調整雙字元件的解碼順序,對于Modicon PLC,請設置為“2-3412”順序解碼。
32 位浮點數解碼順序 舉例:0x3F80 0000
0―1234 表示雙字元件不做處理直接解碼(默認值) 表示 1.0
1―2143 表示雙字元件高低字不顛倒,但字內高低字節顛倒 表示-5.78564e-039
2—3412表示雙字元件高低字顛倒,但字內高低字節不顛倒??表示2.27795e-041
3—4321表示雙字元件內4 個字節全部顛倒 表示 4.60060e-041
(9)校驗方式: 選擇LRC校驗值的組合方式, 對于 Modicon PLC及標準 PLC 設備,
使用默認設置即可。
0—LH[低字節,高字節]:校驗結果為2 個字節,低字節在前,高字節在后。
1—HL[高字節,低字節]:校驗結果為2 個字節,高字節在前,低字節在后。默認值。
(10)分塊采集方式:驅動采集數據分塊的方式,對于Modicon PLC及標準 PLC設備,使用默認設置可以提高采集效率。
0— 按最大長度分塊:采集分塊按最大塊長處理,對地址不連續但地址相近的多個分塊,分為一塊一次性讀取,以優化采集效率。
1— 按連續地址分塊:采集分塊按地址連續性處理,對地址不連續的多個分塊,每次只采集連續地址,不做優化處理。
例如:有4區寄存器地址分別為 1~5,7,9~12的數據需采集,如果選擇“0-按最大長度分塊” ,則兩塊可優化為地址1~12的數據打包1次完成采集;如果選擇“1-按連續地址分塊” ,則需要采集 3 次。
(11)4區16 位寫功能碼選擇:寫 4 區單字時功能碼的選擇,這個屬性主要是針對自己制作設備的用戶而設置的,這樣的設備4區單字寫可能只支持 0x10 功能碼,而不支持0x06 功能碼。
0—0x06:單字寫功能碼使用0x06。
1—0x10:單字寫功能碼使用0x10。
注意:
(1). “解碼順序”及“校驗方式”設置:主要是針對非標準 ModbusRTU 協議的不同解碼及校驗順序。當用戶通過本驅動軟件與設備通訊時,如果出現解析數據值不對,或者通訊校驗錯誤(通訊狀態為3),可與廠家咨詢后對以上兩項進行設置。而對于ModiconPLC及支持標準ModbusRTU 的 PLC 及控制器等設備,一般需將“32位整數解碼順序”和“32位浮點數解碼順序”設置為“2-3412” 。 另外,在使用本驅動與“Modbus 串口數據轉發設備”構件通訊時, “解碼順序”及“校驗方式”均需按默認值設置,否則會導致通訊失敗或解析數據錯誤。
(2). “分塊采集方式”設置:主要是針對非標準 ModbusRTU協議設備。當用戶通過本驅動軟件與設備通訊時,如果按默認“0-按最大長度分塊”時,出現讀取連續地址正常,而不連續地址不正常時,可與廠家咨詢,并設置為“1-按連續地址分塊方式”嘗試是否可正常通訊。 而對于 Modicon PLC 及支持標準 ModbusRTU 的 PLC 及控制器等設備,直接使用默認設置即可,這樣可以提高采集效率。
http://blog.csdn.net/gshgsh1228/article/details/51218306
5、lrc和crc校驗算法
//--------------------------------------------------------------------------
// Constants
//--------------------------------------------------------------------------
static const uint16_t modbus_crc_table[256] = {
? ?0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
? ?0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
? ?0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
? ?0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
? ?0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
? ?0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
? ?0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
? ?0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
? ?0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
? ?0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
? ?0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
? ?0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
? ?0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
? ?0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
? ?0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
? ?0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
? ?0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
? ?0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
? ?0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
? ?0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
? ?0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
? ?0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
? ?0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
? ?0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
? ?0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
? ?0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
? ?0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
? ?0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
? ?0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
? ?0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
? ?0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
? ?0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
?
//--------------------------------------------------------------------------
// Modbus functions
//--------------------------------------------------------------------------
uint8_t modbus_lrc_calc(uint8_t *data, uint16_t len)
{
? ?uint8_t lrc = 0U;
? ?int i;
?
? ?for (i = 0U; i < len; i++)
? ?{
? ? ? lrc += data[i];
? ?}
? ?lrc = (0xFFU - lrc)+1U;
? ?return(lrc);
}
?
uint16_t modbus_crc_calc(uint8_t *buffer, uint16_t size)
{
? ?uint16_t crc = 0xFFFFU;?
? ?uint8_t nTemp;
?
? ? while (size--)
? ? {
? ? ? ? nTemp = *buffer++ ^ crc;
? ? ? ? crc >>= 8;
? ? ? ? crc ?^= modbus_crc_table[(nTemp & 0xFFU)];
? ? }
?
? ?return(crc);
}
LRC算出來的是16進制的字節值,若發送的數據是字符串形式,不需任何轉換,直接放在字符串最后位置就行了。若發送的數據是數組形式,則需要轉換為ASCII值,即由1字節的16進制轉換為2字節的ASCII值,4D應該轉換為34 44。
如果你的發送指令是:com.output="xxxxx",就是字符串形式;
如果發送指令形式是:com.output=A[],就是數組形式。
但不管是哪種形式,ModBus ASCII模式最終在數據線上的數據都是ASCII值。字符串形式的數據,編譯軟件會自動轉換。
6、調試工具
Modbus Poll是一個Modbus管理模擬器軟件,幫助開發人員進行管理和監控的Mod bus數據區在同一時間和模擬Mod bus協議。支持Modbus RTU / ASCII和Modbus TCP / IP協議。
下載地址:http://www.downcc.com/soft/25945.html
modbus slave是一款功能強大的modbus子設備模擬工具,可以幫助modbus通訊設備開發人員進行modbus通訊協議的模擬和測試,用于模擬、測試、調試modbus通訊設備。
下載地址:http://www.ddooo.com/softdown/70166.htm
?7、modbus開源項目
https://github.com/stephane/libmodbus
vc2008 版本下載:http://download.csdn.net/download/byxdaz/10011387
參考資料
http://www.cnblogs.com/luomingui/archive/2013/06/14/Modbus.html
————————————————
版權聲明:本文為CSDN博主「byxdaz」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/byxdaz/article/details/77892778
總結
以上是生活随笔為你收集整理的Modbus学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 境界的彼方_lduoj_bfs宽搜
- 下一篇: C语言零基础入门习题(八)四则运算