Modbus 協(xié)議是應用于電子控制器上的一種通用語(yǔ)言。通過(guò)此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò )(例如以太網(wǎng))和其它設備之間可以通信。它已經(jīng)成為一通用工業(yè)標準。有了它,不同廠(chǎng)商生產(chǎn)的控制設備可以連成工業(yè)網(wǎng)絡(luò ),進(jìn)行集中監控。此協(xié)議定義了一個(gè)控制器能認識使用的消息結構,而不管它們是經(jīng)過(guò)何種網(wǎng)絡(luò )進(jìn)行通信的。它描述了一控制器請求訪(fǎng)問(wèn)其它設備的過(guò)程,如果回應來(lái)自其它設備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內容的公共格式。 當在一Modbus網(wǎng)絡(luò )上通信時(shí),此協(xié)議決定了每個(gè)控制器須要知道它們的設備地址,識別按地址發(fā)來(lái)的消息,決定要產(chǎn)生何種行動(dòng)。如果需要回應,控制器將生成反饋信息并用Modbus協(xié)議發(fā)出。在其它網(wǎng)絡(luò )上,包含了Modbus協(xié)議的消息轉換為在此網(wǎng)絡(luò )上使用的幀或包結構。這種轉換也擴展了根據具體的網(wǎng)絡(luò )解決節地址、路由路徑及錯誤檢測的方法。
在Modbus網(wǎng)絡(luò )上轉輸
標準的Modbus口是使用一RS-232C兼容串行接口,它定義了連接口的針腳、電纜、信號位、傳輸波特率、奇偶校驗??刂破髂苤苯踊蚪?jīng)由Modem組網(wǎng)。 控制器通信使用主—從技術(shù),即僅一設備(主設備)能初始化傳輸(查詢(xún))。其它設備(從設備)根據主設備查詢(xún)提供的數據作出相應反應。典型的主設備:主機和可編程儀表。典型的從設備:可編程控制器。 主設備可單獨和從設備通信,也能以廣播方式和所有從設備通信。如果單獨通信,從設備返回一消息作為回應,如果是以廣播方式查詢(xún)的,則不作任何回應。Modbus協(xié)議建立了主設備查詢(xún)的格式:設備(或廣播)地址、功能代碼、所有要發(fā)送的數據、一錯誤檢測域。 從設備回應消息也由Modbus協(xié)議構成,包括確認要行動(dòng)的域、任何要返回的數據、和一錯誤檢測域。如果在消息接收過(guò)程中發(fā)生一錯誤,或從設備不能執行其命令,從設備將建立一錯誤消息并把它作為回應發(fā)送出去。
在其它類(lèi)型網(wǎng)絡(luò )上轉輸
在其它網(wǎng)絡(luò )上,控制器使用對等技術(shù)通信,故任何控制都能初始和其它控制器的通信。這樣在單獨的通信過(guò)程中,控制器既可作為主設備也可作為從設備。提供的多個(gè)內部通道可允許同時(shí)發(fā)生的傳輸進(jìn)程。 在消息位,Modbus協(xié)議仍提供了主—從原則,盡管網(wǎng)絡(luò )通信方法是“對等”。如果一控制器發(fā)送一消息,它只是作為主設備,并期望從從設備得到回應。同樣,當控制器接收到一消息,它將建立一從設備回應格式并返回給發(fā)送的控制器。
查詢(xún)—回應周期
(1)查詢(xún) 查詢(xún)消息中的功能代碼告之被選中的從設備要執行何種功能。數據段包含了從設備要執行功能的任何附加信息。例如功能代碼03是要求從設備讀保持寄存器并返回它們的內容。數據段必須包含要告之從設備的信息:從何寄存器開(kāi)始讀及要讀的寄存器數量。錯誤檢測域為從設備提供了一種驗證消息內容是否正確的方法。 ?。?)回應 如果從設備產(chǎn)生一正常的回應,在回應消息中的功能代碼是在查詢(xún)消息中的功能代碼的回應。數據段包括了從設備收集的數據:象寄存器值或狀態(tài)。如果有錯誤發(fā)生,功能代碼將被修改以用于指出回應消息是錯誤的,同時(shí)數據段包含了描述此錯誤信息的代碼。錯誤檢測域允許主設備確認消息內容是否可用。
兩種傳輸方式
控制器能設置為兩種傳輸模式(ASCII或RTU)中的任何一種在標準的Modbus網(wǎng)絡(luò )通信。用戶(hù)選擇想要的模式,包括串口通信參數(波特率、校驗方式等),在配置每個(gè)控制器的時(shí)候,在一個(gè)Modbus網(wǎng)絡(luò )上的所有設備都必須選擇相同的傳輸模式和串口參數。 所選的ASCII或RTU方式僅適用于標準的Modbus網(wǎng)絡(luò ),它定義了在這些網(wǎng)絡(luò )上連續傳輸的消息段的每一位,以及決定怎樣將信息打包成消息域和如何解碼。 在其它網(wǎng)絡(luò )上(象MAP和Modbus Plus)Modbus消息被轉成與串行傳輸無(wú)關(guān)的幀。 1、ASCII模式 當控制器設為在Modbus網(wǎng)絡(luò )上以ASCII(美國標準信息交換代碼)模式通信,在消息中的每個(gè)8Bit字節都作為兩個(gè)ASCII字符發(fā)送。這種方式的主要優(yōu)點(diǎn)是字符發(fā)送的時(shí)間間隔可達到1秒而不產(chǎn)生錯誤。 代碼系統 · 十六進(jìn)制,ASCII字符0...9,A...F · 消息中的每個(gè)ASCII字符都是一個(gè)十六進(jìn)制字符組成 每個(gè)字節的位 · 1個(gè)起始位 · 7個(gè)數據位,最小的有效位先發(fā)送 · 1個(gè)奇偶校驗位,無(wú)校驗則無(wú) CRC域是兩個(gè)字節,包含一16位的二進(jìn)制值。它由傳輸設備計算后加入到消息中。接收設備重新計算收到消息的CRC,并與接收到的CRC域中的值比較,如果兩值不同,則有誤。 CRC是先調入一值是全“1”的16位寄存器,然后調用一過(guò)程將消息中連續的8位字節各當前寄存器中的值進(jìn)行處理。僅每個(gè)字符中的8Bit數據對CRC有效,起始位和停止位以及奇偶校驗位均無(wú)效。 CRC產(chǎn)生過(guò)程中,每個(gè)8位字符都單獨和寄存器內容相或(OR),結果向最低有效位方向移動(dòng),最高有效位以0填充。LSB被提取出來(lái)檢測,如果LSB為1,寄存器單獨和預置的值或一下,如果LSB為0,則不進(jìn)行。整個(gè)過(guò)程要重復8次。在最后一位(第8位)完成后,下一個(gè)8位字節又單獨和寄存器的當前值相或。最終寄存器中的值,是消息中所有的字節都執行之后的CRC值。
CRC添加到消息中時(shí),低字節先加入,然后高字節。
CRC簡(jiǎn)單函數如下: unsigned short CRC16(puchMsg, usDataLen) unsigned char *puchMsg ; /* 要進(jìn)行CRC校驗的消息 */
unsigned short usDataLen ; /* 消息中字節數 */
{
unsigned char uchCRCHi = 0xFF ; /* 高CRC字節初始化 */
unsigned char uchCRCLo = 0xFF ; /* 低CRC 字節初始化 */
unsigned uIndex ; /* CRC循環(huán)中的索引 */
while (usDataLen--) /* 傳輸消息緩沖區 */
{
uIndex = uchCRCHi ^ *puchMsgg++ ; /* 計算CRC */
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex} ;
uchCRCLo = auchCRCLo[uIndex] ;
}
return (uchCRCHi << 8 uchCRCLo) ;
}
/* CRC 高位字節值表 */
static unsigned char auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
/* CRC低位字節值表*/ static char auchCRCLo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 } ;
ModBus網(wǎng)絡(luò )是一個(gè)工業(yè)通信系統,由帶智能終端的可編程序控制器和計算機通過(guò)公用線(xiàn)路或局部專(zhuān)用線(xiàn)路連接而成。其系統結構既包括硬件、亦包括軟件。它可應用于各種數據采集和過(guò)程監控。下表1是ModBus的功能碼定義。
表1 ModBus功能碼
01 READ COIL STATUS
02 READ INPUT STATUS
03 READ HOLDING REGISTER
04 READ INPUT REGISTER
05 WRITE SINGLE COIL
06 WRITE SINGLE REGISTER
15 WRITE MULTIPLE COIL
16 WRITE MULTIPLE REGISTER
ModBus網(wǎng)絡(luò )只是一個(gè)主機,所有通信都由他發(fā)出。網(wǎng)絡(luò )可支持247個(gè)之多的遠程從屬控制器,但實(shí)際所支持的從機數要由所用通信設備決定。采用這個(gè)系統,各PC可以和中心主機交換信息而不影響各PC執行本身的控制任務(wù)。
(1)ModBus的傳輸方式
在ModBus系統中有2種傳輸模式可選擇。這2種傳輸模式與從機PC通信的能力是同等的。選擇時(shí)應視所用ModBus主機而定,每個(gè)ModBus系統只能使用一種模式,不允許2種模式混用。一種模式是ASCII(美國信息交換碼),另一種模式是RTU(遠程終端設備)這兩種模式的定義見(jiàn)表3
表3 ASCII和RTU傳輸模式的特性
ASCII可打印字符便于故障檢測,而且對于用高級語(yǔ)言(如Fortan)編程的主計算機及主PC很適宜。RTU則適用于機器語(yǔ)言編程的計算機和PC主機。 用RTU模式傳輸的數據是8位二進(jìn)制字符。如欲轉換為ASCII模式,則每個(gè)RTU字符首先應分為高位和低位兩部分,這兩部分各含4位,然后轉換成十六進(jìn)制等量值。用以構成報文的ASCII字符都是十六進(jìn)制字符。ASCII模式使用的字符雖是RTU模式的兩倍,但ASCII數據的譯瑪和處理更為容易一些,此外,用RTU模式時(shí)報文字符必須以連續數據流的形式傳送,用ASCII模式,字符之間可產(chǎn)生長(cháng)達1s的間隔,以適應速度較快的機器。
(2)ModBus的數據校驗方式
CRC-16(循環(huán)冗余錯誤校驗)
CRC-16錯誤校驗程序如下:
報文(此處只涉及數據位,不指起始位、停止位和任選的奇偶校驗位)被看作是一個(gè)連續的二進(jìn)制,其最高有效位(MSB)首選發(fā)送。報文先與X↑16相乘(左移16位),然后看X↑16+X↑15+X↑2+1除,X↑16+X↑15+X↑2+1可以表示為二進(jìn)制數11000000000000101。整數商位忽略不記,16位余數加入該報文(MSB先發(fā)送),成為2個(gè)CRC校驗字節。余數中的1全部初始化,以免所有的零成為一條報文被接收。經(jīng)上述處理而含有CRC字節的報文,若無(wú)錯誤,到接收設備后再被同一多項式(X↑16+X↑15+X↑2+1)除,會(huì )得到一個(gè)零余數(接收設備核驗這個(gè)CRC字節,并將其與被傳送的CRC比較)。全部運算以2為模(無(wú)進(jìn)位)。
習慣于成串發(fā)送數據的設備會(huì )首選送出字符的最右位(LSB-最低有效位)。而在生成CRC情況下,發(fā)送首位應是被除數的最高有效位MSB。由于在運算中不用進(jìn)位,為便于操作起見(jiàn),計算CRC時(shí)設MSB在最右位。生成多項式的位序也必須反過(guò)來(lái),以保持一致。多項式的MSB略去不記,因其只對商有影響而不影響余數。
生成CRC-16校驗字節的步驟如下:
①裝如一個(gè)16位寄存器,所有數位均為1。
②該16位寄存器的高位字節與開(kāi)始8位字節進(jìn)行“異或”運算。運算結果放入這個(gè)16位寄存器。
③把這個(gè)16寄存器向右移一位。
④若向右(標記位)移出的數位是1,則生成多項式1010000000000001和這個(gè)寄存器進(jìn)行“異或”運算;若向右移出的數位是0,則返回③。
⑤重復③和④,直至移出8位。
⑥另外8位與該十六位寄存器進(jìn)行“異或”運算。
⑦重復③~⑥,直至該報文所有字節均與16位寄存器進(jìn)行“異或”運算,并移位8次。
⑧這個(gè)16位寄存器的內容即2字節CRC錯誤校驗,被加到報文的最高有效位。 另外,在某些非ModBus通信協(xié)議中也經(jīng)常使用CRC16作為校驗手段,而且產(chǎn)生了一些CRC16的變種,他們是使用CRC16多項式X↑16+X↑15+X↑2+1,單首次裝入的16位寄存器為0000;使用CRC16的反序X↑16+X↑14+X↑1+1,首次裝入寄存器值為0000或FFFFH。 LRC(縱向冗余錯誤校驗) LRC錯誤校驗用于A(yíng)SCII模式。這個(gè)錯誤校驗是一個(gè)8位二進(jìn)制數,可作為2個(gè)ASCII十六進(jìn)制字節傳送。把十六進(jìn)制字符轉換成二進(jìn)制,加上無(wú)循環(huán)進(jìn)位的二進(jìn)制字符和二進(jìn)制補碼結果生成LRC錯誤校驗(參見(jiàn)圖)。這個(gè)LRC在接收設備進(jìn)行核驗,并與被傳送的LRC進(jìn)行比較,冒號(:)、回車(chē)符號(CR)、換行字符(LF)和置入的其他任何非ASCII十六進(jìn)制字符在運算時(shí)忽略不計。