Modbus以及上位機(jī)軟件實際運用
轉(zhuǎn)自:https://blog.csdn.net/magicchz/article/details/128900304
Demo代碼
Git代碼示例:https://github.com/chenheze90/Learning01_Modbus/tree/master
Modbus簡介
Modbus是一種串行通訊協(xié)議,通常運用在電子設(shè)備之間的通訊上。在許多制造行業(yè)中應(yīng)用極其廣泛;進(jìn)過多年的發(fā)展Modbus已經(jīng)成為工業(yè)領(lǐng)域通信協(xié)議的業(yè)界標(biāo)準(zhǔn)(De facto),并且現(xiàn)在是工業(yè)電子設(shè)備之間常用的連接方式。
Modbus原本設(shè)計是針對PLC通訊問題而設(shè)計,目前Modbus協(xié)議主要用在串口、以太網(wǎng)和其他互聯(lián)網(wǎng)協(xié)議的網(wǎng)絡(luò),基本上占大部分的Modbus是通過TCP或者485串口進(jìn)行信息交互。
如下所示,Modbus是在應(yīng)用層封裝、解析、傳遞消息的。
協(xié)議版本
ModbusRTU
Modbus RTU是一種緊湊的,采用二進(jìn)制表示數(shù)據(jù)的方式,使用串行通信(serial communication)方式。RTU格式后續(xù)的命令/數(shù)據(jù)帶有循環(huán)冗余校驗的校驗和(CRC)。被配置為RTU變種的節(jié)點不會和設(shè)置為ASCII變種的節(jié)點通信,反之亦然。
ModbusASCII
Modbus ASCII是一種人類可讀的,冗長的表示方式。使用串行通信(serial communication)方式。ASCII格式采用縱向冗余校驗的校驗和(LRC)。相比之下,RTU格式的協(xié)議較為常用。
Modbus/TCP
對于通過TCP/IP(例如以太網(wǎng))的連接,存在多個Modbus/TCP變種,這種方式不需要校驗和計算,目前較為廣泛運用的是Modbus/TCP。
通訊簡析
Modbus協(xié)議是一個master/slave(或者server/client)架構(gòu)的協(xié)議,簡單點理解就是主從結(jié)構(gòu)。有且僅有一個節(jié)點是主節(jié)點,其他使用Modbus協(xié)議參與通信的節(jié)點是子節(jié)點。每一個子設(shè)備都有一個唯一的地址。在以太網(wǎng)上,任何一個設(shè)備都能發(fā)送一個Modbus命令,但是通常也只有一個主節(jié)點設(shè)備啟動指令。
一個ModBus命令包含了打算執(zhí)行的設(shè)備的Modbus地址。所有設(shè)備都會收到命令,但只有指定位置的設(shè)備會執(zhí)行及回應(yīng)指令(地址0例外,指定地址0的指令是廣播指令,所有收到指令的設(shè)備都會運行,不過不回應(yīng)指令)。所有的Modbus命令包含了檢查碼,以確定到達(dá)的命令沒有被破壞。基本的ModBus命令能指令一個RTU改變它的寄存器的某個值,控制或者讀取一個I/O端口,以及指揮設(shè)備回送一個或者多個其寄存器中的數(shù)據(jù)。
有許多modems和網(wǎng)關(guān)支持Modbus協(xié)議,因為Modbus協(xié)議很簡單而且容易復(fù)制。它們當(dāng)中一些為這個協(xié)議特別設(shè)計的。有使用有線、無線通信甚至短消息和GPRS的不同實現(xiàn)。不過設(shè)計者需要克服一些包括高延遲和時序的問題。
錯誤通訊
當(dāng)主機(jī)傳送的報文不符合格式、從機(jī)不支援此功能等問題時,這時從機(jī)就會回復(fù)一個錯誤信息,例子如下
請求數(shù)據(jù):
從機(jī)地址 功能碼 數(shù)據(jù)1 數(shù)據(jù)2 … 數(shù)據(jù)n CRCL CRCH
0x01 0x03 0x01 0x01 0x02 0xd5 0xdd
返回數(shù)據(jù):
從機(jī)地址 功能碼 異常碼 CRCL CRCH
0x01 0x03 0x02 0xd5 0xdd
其中的異常碼如下表所示:
功能碼 名稱 說明
01 ILLEGAL FUNCTION 不支援的功能
02 LLEGAL DATA ADDRESS 不合法的地址
03 ILLEGAL DATA VALUE 不合法的數(shù)值
04 SLAVE DEVICE FAILURE Slave 失效
05 ACKNOWLEDGE 命令執(zhí)行中
06 SLAVE DEVICE BUSY Slave 忙碌
寄存器/暫存器
寄存器分四類
類別 區(qū)號 讀寫 值范圍
線圈狀態(tài) 0區(qū) 可讀可寫布爾量 00001-09999
離散輸入狀態(tài) 1區(qū) 只讀布爾量 10001-19999
輸入寄存器 3區(qū) 只讀寄存器 30001-39999
保持寄存器 4區(qū) 可讀可寫寄存器 40001-49999
并且Modbus還給每個區(qū)都劃分了地址范圍 主機(jī)向從機(jī)獲取數(shù)據(jù)時,只需要告訴從機(jī)數(shù)據(jù)的起始地址,還有獲取多少字節(jié)的數(shù)據(jù),從機(jī)就可以發(fā)送數(shù)據(jù)給主機(jī)。
Modbus數(shù)據(jù)模型規(guī)定了具體的地址范圍,每一個從機(jī),都有實際的物理存儲,跟modbus的存儲區(qū)相對應(yīng),主機(jī)讀寫從機(jī)的存儲區(qū),實際上就是對從機(jī)設(shè)備對應(yīng)的實際存儲空間進(jìn)行讀寫。
RTU協(xié)議幀結(jié)構(gòu)
RTU是常用的一種協(xié)議,一個報文就是一幀數(shù)據(jù),實際上是一串有組織的數(shù)據(jù)串。
?幀結(jié)構(gòu):主要由從機(jī)地址/功能嗎/數(shù)據(jù)/校驗組成。
?從機(jī)地址: 每個從機(jī)都有一個地址,占用一個字節(jié),范圍0-255,其中有效范圍是1-247,其中255是廣播地址,剩余的地址用于高級開發(fā)。
?功能碼: 占用一個字節(jié),下文會介紹。
?數(shù)據(jù): 各種參數(shù),配合功能碼實現(xiàn)功能,功能碼比作方法,數(shù)據(jù)就是方法的參數(shù)。
?校驗: 對上面的數(shù)據(jù)進(jìn)行一個有規(guī)律的計算得出的值就是CRC校驗碼,CRC檢驗數(shù)據(jù)是否完整。
CRC校驗
CRC占用兩個字節(jié)包含了一個16位的二進(jìn)制值,如上表所示的CRCL和CRCH。這兩個值在發(fā)出的時候已經(jīng)由發(fā)出的設(shè)備計算得出,然后附加到數(shù)據(jù)幀尾部,接收設(shè)備在接收數(shù)據(jù)時重新計算CRC值,然后與接收到的CRC域中的值進(jìn)行比較,如果這兩個值不相等就判斷數(shù)據(jù)發(fā)生了錯誤。
功能碼
Modbus規(guī)定了多個功能,那么為了方便的使用這些功能,我們給每個功能都設(shè)定一個功能碼,也就是指代碼。
功能碼 功能說明
01H 讀取輸出線圈
02H 讀取輸入線圈
03H 讀取保持寄存器
04H 讀取輸入寄存器
05H 寫入單線圈
06H 寫入單寄存器
0FH 寫入多線圈
10H 寫入多寄存器
Modbus協(xié)議同時規(guī)定了二十幾種功能碼,但是常用的只有8種,用于對存儲區(qū)的讀寫。
上位機(jī)代碼實例
ModbusSlave
ModbusSlave是modbus常見的調(diào)試工具,可以模擬32個子設(shè)備。首先下載ModbusSlave。地址: https://www.pcsoft.com.cn/soft/197832.html
安裝過程此處省略,直接點下一步即可。
TCP協(xié)議
Modbus-TCP協(xié)議與Modbus-RTU協(xié)議最大的不同就是多了一個MBAP報文頭,這個是TCP獨有的特征。
MBAP的長度是7個字節(jié),如下圖所示。
?事務(wù)處理標(biāo)識符:類似于信息序列號,確認(rèn)發(fā)出和受到的信息屬于同一個序列,每次通信后就要加1;
?協(xié)議標(biāo)識符:用于系統(tǒng)內(nèi)的多路復(fù)用,當(dāng)它的值是0 (00 00) ,表示使用Modbus協(xié)議;
?長度:用于說明此字節(jié)之后還有多少個字節(jié)的數(shù)量;
?單元標(biāo)識符:即設(shè)備地址,在slave中對應(yīng)其ID;
?功能碼:與Modbus-RTU協(xié)議相似
?數(shù)據(jù):與Modbus-RTU協(xié)議相似
地址類別和RTU類似
功能碼如下:
功能碼 功能說明
01H 讀取輸出線圈
02H 讀取輸入線圈
03H 讀取保持寄存器
04H 讀取輸入寄存器
05H 寫入單線圈
06H 寫入單寄存器
0FH 寫入多線圈
10H 寫入多寄存器
線圈寄存器:實際上就可以類比為開關(guān)量(繼電器狀態(tài)),每一個bit對應(yīng)一個信號的開關(guān)狀態(tài)。所以一個byte就可以同時控制8路的信號。比如控制外部8路io的高低。 線圈寄存器支持讀也支持寫,寫在功能碼里面又分為寫單個線圈寄存器和寫多個線圈寄存器。對應(yīng)上面的功能碼也就是:0x01 0x05 0x0f
離散輸入寄存器:如果線圈寄存器理解了這個自然也明白了。離散輸入寄存器就相當(dāng)于線圈寄存器的只讀模式,他也是每個bit表示一個開關(guān)量,而他的開關(guān)量只能讀取輸入的開關(guān)信號,是不能夠?qū)懙摹1热缥易x取外部按鍵的按下還是松開。所以功能碼也簡單就一個讀的 0x02
保持寄存器:這個寄存器的單位不再是bit而是兩個byte,也就是可以存放具體的數(shù)據(jù)量的,并且是可讀寫的。一般對應(yīng)參數(shù)設(shè)置,比如我我設(shè)置時間年月日,不但可以寫也可以讀出來現(xiàn)在的時間。寫也分為單個寫和多個寫,所以功能碼有對應(yīng)的三個:0x03 0x06 0x10
輸入寄存器:這個和保持寄存器類似,但是也是只支持讀而不能寫,一般是讀取各種實時數(shù)據(jù)。一個寄存器也是占據(jù)兩個byte的空間。類比我我通過讀取輸入寄存器獲取現(xiàn)在的AD采集值。對應(yīng)的功能碼也就一個 0x04
Modebus封裝——NModbus
在vs中打開nuget,下載NModbus插件
下載完成后之后即可進(jìn)行操作數(shù)據(jù)。
讀取線圈數(shù)據(jù)
所有步驟之前,要先聯(lián)接slave,使模擬器上線。
讀取線圈數(shù)據(jù)首先要將模擬器設(shè)置成線圈
然后設(shè)置線圈的值
在代碼中讀取數(shù)據(jù),本次讀取的數(shù)據(jù)是從第1位開始()模擬器有0的位置)開始取5個值
代碼執(zhí)行結(jié)果如下圖所示
讀取離散線圈數(shù)據(jù)
同樣的,讀取離散線圈的數(shù)據(jù),需要將模擬器的功能轉(zhuǎn)成離散模式
此次模擬 讀取0~6的數(shù)據(jù)
結(jié)果如下
讀取保存寄存器
讀取保存寄存器的值:
我們只要讀取從0之后的4個數(shù)據(jù),代碼如下
結(jié)果如下圖所示
讀取輸入寄存器
輸入寄存器和離散線圈一樣,都是只讀。
先設(shè)置模擬器數(shù)據(jù)類型
本次讀取從0開始的4個字符
結(jié)構(gòu)如下所示
寫入單線圈
首先,將模擬器slave調(diào)整成線圈模式
模擬在1這個位置寫入1,在方法中1即true,0即false
寫入單寄存器
單寄存器是兩個byte,主要存儲復(fù)雜的數(shù)據(jù),如時間,文本等。同樣要先設(shè)置模擬器數(shù)據(jù)類型。
然后模擬在第四位寫入一個56,結(jié)果如下圖所示
寫入多線圈
代碼示例
寫入多寄存器
代碼示例
————————————————
版權(quán)聲明:本文為CSDN博主「無形道長」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/magicchz/article/details/128900304
浙公網(wǎng)安備 33010602011771號