1、Modbus 協議簡介 編程
Modbus 協議是應用於電子控制器上的一種通用語言。經過此協議,控制器相互之間、控制器經由網絡(例如以太網)和其它設備之間能夠通訊。它已經成爲一通用工業標準。有了它,不一樣廠商生產的控制設備能夠連成工業網絡,進行集中監控。 安全
此協議定義了一個控制器能認識使用的消息結構,而無論它們是通過何種網絡進行通訊的。它描述了一控制器請求訪問其它設備的過程,若是迴應來自其它設備的請求,以及怎樣偵測錯誤並記錄。它制定了消息域格局和內容的公共格式。 網絡
當在一Modbus網絡上通訊時,此協議決定了每一個控制器需要知道它們的設備地址,識別按地址發來的消息,決定要產生何種行動。若是須要回應,控制器將生成反饋信息並用Modbus協議發出。在其它網絡上,包含了Modbus協議的消息轉換爲在此網絡上使用的幀或包結構。這種轉換也擴展了根據具體的網絡解決節地址、路由路徑及錯誤檢測的方法。函數
一、在Modbus網絡上轉輸編碼
標準的Modbus口是使用一RS-232C兼容串行接口,它定義了鏈接口的針腳、電纜、信號位、傳輸波特率、奇偶校驗。控制器能直接或經由Modem組網。 spa
控制器通訊使用主—從技術,即僅一設備(主設備)能初始化傳輸(查詢)。其它設備(從設備)根據主設備查詢提供的數據做出相應反應。典型的主設備:主機和可編程儀表。典型的從設備:可編程控制器。 code
主設備可單獨和從設備通訊,也能以廣播方式和全部從設備通訊。若是單獨通訊,從設備返回一消息做爲迴應,若是是以廣播方式查詢的,則不做任何迴應。Modbus協議創建了主設備查詢的格式:設備(或廣播)地址、功能代碼、全部要發送的數據、一錯誤檢測域。 blog
從設備迴應消息也由Modbus協議構成,包括確認要行動的域、任何要返回的數據、和一錯誤檢測域。若是在消息接收過程當中發生一錯誤,或從設備不能執行其命令,從設備將創建一錯誤消息並把它做爲迴應發送出去。索引
二、在其它類型網絡上轉輸接口
在其它網絡上,控制器使用對等技術通訊,故任何控制都能初始和其它控制器的通訊。這樣在單獨的通訊過程當中,控制器既可做爲主設備也可做爲從設備。提供的多個內部通道可容許同時發生的傳輸進程。
在消息位,Modbus協議仍提供了主—從原則,儘管網絡通訊方法是「對等」。若是一控制器發送一消息,它只是做爲主設備,並指望從從設備獲得迴應。一樣,當控制器接收到一消息,它將創建一從設備迴應格式並返回給發送的控制器。
三、查詢—迴應週期
(1)查詢
查詢消息中的功能代碼告之被選中的從設備要執行何種功能。數據段包含了從設備要執行功能的任何附加信息。例如功能代碼03是要求從設備讀保持寄存器並返回它們的內容。數據段必須包含要告之從設備的信息:從何寄存器開始讀及要讀的寄存器數量。錯誤檢測域爲從設備提供了一種驗證消息內容是否正確的方法。
(2)迴應
若是從設備產生一正常的迴應,在迴應消息中的功能代碼是在查詢消息中的功能代碼的迴應。數據段包括了從設備收集的數據:象寄存器值或狀態。若是有錯誤發生,功能代碼將被修改以用於指出迴應消息是錯誤的,同時數據段包含了描述此錯誤信息的代碼。錯誤檢測域容許主設備確認消息內容是否可用。
2、兩種傳輸方式
控制器能設置爲兩種傳輸模式(ASCII或RTU)中的任何一種在標準的Modbus網絡通訊。用戶選擇想要的模式,包括串口通訊參數(波特率、校驗方式等),在配置每一個控制器的時候,在一個Modbus網絡上的全部設備都必須選擇相同的傳輸模式和串口參數。
ASCII模式
: | 地址 | 功能代碼 | 數據數量 | 數據1 | ... | 數據n | LRC高字節 | LRC低字節 | 回車 | 換行 |
RTU模式
地址 | 功能代碼 | 數據數量 | 數據1 | ... | 數據n | CRC低字節 | CRC高字節 |
所選的ASCII或RTU方式僅適用於標準的Modbus網絡,它定義了在這些網絡上連續傳輸的消息段的每一位,以及決定怎樣將信息打包成消息域和如何解碼。
在其它網絡上(象MAP和Modbus Plus)Modbus消息被轉成與串行傳輸無關的幀。
一、ASCII模式
當控制器設爲在Modbus網絡上以ASCII(美國標準信息交換代碼)模式通訊,在消息中的每一個8Bit字節都做爲兩個ASCII字符發送。這種方式的主要優勢是字符發送的時間間隔可達到1秒而不產生錯誤。
代碼系統
每一個字節的位
錯誤檢測域
LRC(縱向冗長檢測)
二、RTU模式
當控制器設爲在Modbus網絡上以RTU(遠程終端單元)模式通訊,在消息中的每一個8Bit字節包含兩個4Bit的十六進制字符。這種方式的主要優勢是:在一樣的波特率下,可比ASCII方式傳送更多的數據。
代碼系統
錯誤檢測域
3、Modbus消息幀
兩種傳輸模式中(ASCII或RTU),傳輸設備以將Modbus消息轉爲有起點和終點的幀,這就容許接收的設備在消息起始處開始工做,讀地址分配信息,判斷哪個設備被選中(廣播方式則傳給全部設備),判知什麼時候信息已完成。部分的消息也能偵測到而且錯誤能設置爲返回結果。
一、ASCII幀
使用ASCII模式,消息以冒號(:)字符(ASCII碼 3AH)開始,以回車換行符結束(ASCII碼 0DH,0AH)。
其它域可使用的傳輸字符是十六進制的0...9,A...F。網絡上的設備不斷偵測「:」字符,當有一個冒號接收到時,每一個設備都解碼下個域(地址域)來判斷是否發給本身的。
消息中字符間發送的時間間隔最長不能超過1秒,不然接收的設備將認爲傳輸錯誤。一個典型消息幀以下所示:
起始位 | 設備地址 | 功能代碼 | 數據 | LRC校驗 | 結束符 |
1個字符 | 2個字符 | 2個字符 | n個字符 | 2個字符 | 2個字符 |
圖2 ASCII消息幀
二、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 |
圖3 RTU消息幀
三、地址域
消息幀的地址域包含兩個字符(ASCII)或8Bit(RTU)。可能的從設備地址是0...247 (十進制)。單個設備的地址範圍是1...247。主設備經過將要聯絡的從設備的地址放入消息中的地址域來選通從設備。當從設備發送迴應消息時,它把本身的地址放入迴應的地址域中,以便主設備知道是哪個設備做出迴應。
地址0是用做廣播地址,以使全部的從設備都能認識。當Modbus協議用於更高水準的網絡,廣播可能不容許或以其它方式代替。
四、如何處理功能域
消息幀中的功能代碼域包含了兩個字符(ASCII)或8Bits(RTU)。可能的代碼範圍是十進制的1...255。固然,有些代碼是適用於全部控制器,有此是應用於某種控制器,還有些保留以備後用。
當消息從主設備發往從設備時,功能代碼域將告之從設備須要執行哪些行爲。例如去讀取輸入的開關狀態,讀一組寄存器的數據內容,讀從設備的診斷狀態,容許調入、記錄、校驗在從設備中的程序等。
當從設備迴應時,它使用功能代碼域來指示是正常回應(無誤)仍是有某種錯誤發生(稱做異議迴應)。對正常回應,從設備僅迴應相應的功能代碼。對異議迴應,從設備返回一等同於正常代碼的代碼,但最重要的位置爲邏輯1。
例如:一從主設備發往從設備的消息要求讀一組保持寄存器,將產生以下功能代碼:0 0 0 0 0 0 1 1 (十六進制03H)
對正常回應,從設備僅迴應一樣的功能代碼。對異議迴應,它返回:1 0 0 0 0 0 1 1 (十六進制83H)
除功能代碼因異議錯誤做了修改外,從設備將一獨特的代碼放到迴應消息的數據域中,這能告訴主設備發生了什麼錯誤。
主設備應用程序獲得異議的迴應後,典型的處理過程是重發消息,或者診斷髮給從設備的消息並報告給操做員。
五、數據域
數據域是由兩個十六進制數集合構成的,範圍00...FF。根據網絡傳輸模式,這能夠是由一對ASCII字符組成或由一RTU字符組成。
從主設備發給從設備消息的數據域包含附加的信息:從設備必須用於進行執行由功能代碼所定義的所爲。這包括了象不連續的寄存器地址,要處理項的數目,域中實際數據字節數。
例如,若是主設備須要從設備讀取一組保持寄存器(功能代碼03),數據域指定了起始寄存器以及要讀的寄存器數量。若是主設備寫一組從設備的寄存器(功能代碼10十六進制),數據域則指明瞭要寫的起始寄存器以及要寫的寄存器數量,數據域的數據字節數,要寫入寄存器的數據。
若是沒有錯誤發生,從從設備返回的數據域包含請求的數據。若是有錯誤發生,此域包含一異議代碼,主設備應用程序能夠用來判斷採起下一步行動。
在某種消息中數據域能夠是不存在的(0長度)。例如,主設備要求從設備迴應通訊事件記錄(功能代碼0B十六進制),從設備不需任何附加的信息。
六、錯誤檢測域
標準的Modbus網絡有兩種錯誤檢測方法。錯誤檢測域的內容視所選的檢測方法而定。
ASCII
當選用ASCII模式做字符幀,錯誤檢測域包含兩個ASCII字符。這是使用LRC(縱向冗長檢測)方法對消息內容計算得出的,不包括開始的冒號符及回車換行符。LRC字符附加在回車換行符前面。
RTU
當選用RTU模式做字符幀,錯誤檢測域包含一16Bits值(用兩個8位的字符來實現)。錯誤檢測域的內容是經過對消息內容進行循環冗長檢測方法得出的。CRC域附加在消息的最後,添加時先是低字節而後是高字節。故CRC的高位字節是發送消息的最後一個字節。
七、字符的連續傳輸
當消息在標準的Modbus系列網絡傳輸時,每一個字符或字節以以下方式發送(從左到右):
最低有效位...最高有效位
使用ASCII字符幀時,位的序列是:
有奇偶校驗
啓始位 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 奇偶位 | 中止位 |
無奇偶校驗
啓始位 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 中止位 | 中止位 |
圖4. 位順序(ASCII)
使用RTU字符幀時,位的序列是:
有奇偶校驗
啓始位 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 奇偶位 | 中止位 |
無奇偶校驗
啓始位 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 中止位 | 中止位 |
圖4. 位順序(RTU)
4、錯誤檢測方法
標準的Modbus串行網絡採用兩種錯誤檢測方法。奇偶校驗對每一個字符均可用,幀檢測(LRC或CRC)應用於整個消息。它們都是在消息發送前由主設備產生的,從設備在接收過程當中檢測每一個字符和整個消息幀。
用戶要給主設備配置一預先定義的超時時間間隔,這個時間間隔要足夠長,以使任何從設備都能做爲正常反應。若是從設備測到一傳輸錯誤,消息將不會接收,也不會向主設備做出迴應。這樣超時事件將觸發主設備來處理錯誤。發往不存在的從設備的地址也會產生超時。
一、奇偶校驗
用戶能夠配置控制器是奇或偶校驗,或無校驗。這將決定了每一個字符中的奇偶校驗位是如何設置的。
若是指定了奇或偶校驗,「1」的位數將算到每一個字符的位數中(ASCII模式7個數據位,RTU中8個數據位)。例如RTU字符幀中包含如下8個數據位:1 1 0 0 0 1 0 1
整個「1」的數目是4個。若是便用了偶校驗,幀的奇偶校驗位將是0,便得整個「1」的個數還是4個。若是便用了奇校驗,幀的奇偶校驗位將是1,便得整個「1」的個數是5個。
若是沒有指定奇偶校驗位,傳輸時就沒有校驗位,也不進行校驗檢測。代替一附加的中止位填充至要傳輸的字符幀中。
二、LRC檢測
使用ASCII模式,消息包括了一基於LRC方法的錯誤檢測域。LRC域檢測了消息域中除開始的冒號及結束的回車換行號外的內容。
LRC域是一個包含一個8位二進制值的字節。LRC值由傳輸設備來計算並放到消息幀中,接收設備在接收消息的過程當中計算LRC,並將它和接收到消息中LRC域中的值比較,若是兩值不等,說明有錯誤。
LRC方法是將消息中的8Bit的字節連續累加,丟棄了進位。
LRC簡單函數以下:
///C代碼
static unsigned char LRC(auchMsg,usDataLen)
unsigned char *auchMsg ; /* 要進行計算的消息 */ unsigned short usDataLen ; /* LRC 要處理的字節的數量*/ {
unsigned char uchLRC = 0 ; /* LRC 字節初始化 */ while (usDataLen--) /* 傳送消息 */ uchLRC += *auchMsg++ ; /* 累加*/ return ((unsigned char)(-((char_uchLRC))) ; }
三、CRC檢測
使用RTU模式,消息包括了一基於CRC方法的錯誤檢測域。CRC域檢測了整個消息的內容。
CRC域是兩個字節,包含一16位的二進制值。它由傳輸設備計算後加入到消息中。接收設備從新計算收到消息的CRC,並與接收到的CRC域中的值比較,若是兩值不一樣,則有誤。
CRC是先調入一值是全「1」的16位寄存器,而後調用一過程將消息中連續的8位字節各當前寄存器中的值進行處理。僅每一個字符中的8Bit數據對CRC有效,起始位和中止位以及奇偶校驗位均無效。
CRC產生過程當中,每一個8位字符都單獨和寄存器內容相或(OR),結果向最低有效位方向移動,最高有效位以0填充。LSB被提取出來檢測,若是LSB爲1,寄存器單獨和預置的值或一下,若是LSB爲0,則不進行。整個過程要重複8次。在最後一位(第8位)完成後,下一個8位字節又單獨和寄存器的當前值相或。最終寄存器中的值,是消息中全部的字節都執行以後的CRC值。
CRC添加到消息中時,低字節先加入,而後高字節。
MODBUS通信協議及編程【二】
ModBus通信協議分爲RTU協議和ASCII協議,我公司的多種儀表都採用ModBus RTU通信協議,如:CH2000智能電力監測儀、CH2000M電力參數採集模塊、巡檢表、數顯表、光柱數顯表等。下面就ModBus RTU協議簡要介紹以下:
1、通信協議
(一)、通信傳送方式:
通信傳送分爲獨立的信息頭,和發送的編碼數據。如下的通信傳送方式定義也與MODBUS RTU通信規約相兼容:
編 碼
|
8位二進制
|
起始位
|
1位
|
數據位
|
8位
|
奇偶校驗位
|
1位(偶校驗位)
|
中止位
|
1位
|
錯誤校檢
|
CRC(冗餘循環碼)
|
初始結構 = ≥4字節的時間
地址碼 = 1 字節
功能碼 = 1 字節
數據區 = N 字節
錯誤校檢 = 16位CRC碼
結束結構 = ≥4字節的時間
地址碼:地址碼爲通信傳送的第一個字節。這個字節代表由用戶設定地址碼的從機將接收由主機發送來的信息。而且每一個從機都有具備惟一的地址碼,而且響應回送均以各自的地址碼開始。主機發送的地址碼代表將發送到的從機地址,而從機發送的地址碼代表回送的從機地址。
功能碼:通信傳送的第二個字節。ModBus通信規約定義功能號爲1到127。本儀表只利用其中的一部分功能碼。做爲主機請求發送,經過功能碼告訴從機執行什麼動做。做爲從機響應,從機發送的功能碼與從主機發送來的功能碼同樣,並代表從機已響應主機進行操做。若是從機發送的功能碼的最高位爲1(好比功能碼大與此同時127),則代表從機沒有響應操做或發送出錯。
數據區:數據區是根據不一樣的功能碼而不一樣。數據區能夠是實際數值、設置點、主機發送給從機或從機發送給主機的地址。
CRC碼:二字節的錯誤檢測碼。
(二)、通信規約:
當通信命令發送至儀器時,符合相應地址碼的設備接通信命令,併除去地址碼,讀取信息,若是沒有出錯,則執行相應的任務;而後把執行結果返送給發送者。返送的信息中包括地址碼、執行動做的功能碼、執行動做後結果的數據以及錯誤校驗碼。若是出錯就不發送任何信息。
1.信息幀結構
地址碼
|
功能碼
|
數據區
|
錯誤校驗碼
|
8位
|
8位
|
N × 8位
|
16位
|
地址碼:地址碼是信息幀的第一字節(8位),從0到255。這個字節代表由用戶設置地址的從機將接收由主機發送來的信息。每一個從機都必須有惟一的地址碼,而且只有符合地址碼的從機才能響應回送。當從機回送信息時,至關的地址碼代表該信息來自於何處。
功能碼:主機發送的功能碼告訴從機執行什麼任務。表1-1列出的功能碼都有具體的含義及操做。
代碼
|
含義
|
操做
|
03 | 讀取數據 | 讀取當前寄存器內一個或多個二進制值 |
06 | 重置單一寄存器 | 把設置的二進制值寫入單一寄存器 |
數據區:數據區包含須要從機執行什麼動做或由從機採集的返送信息。這些信息能夠是數值、參考地址等等。例如,功能碼告訴從機讀取寄存器的值,則數據區必需包含要讀取寄存器的起始地址及讀取長度。對於不一樣的從機,地址和數據信息都不相同。
錯誤校驗碼:主機或從機可用校驗碼進行判別接收信息是否出錯。有時,因爲電子噪聲或其它一些干擾,信息在傳輸過程當中會發生細微的變化,錯誤校驗碼保證了主機或從機對在傳送過程當中出錯的信息不起做用。這樣增長了系統的安全和效率。錯誤校驗採用CRC-16校驗方法。
注:信息幀的格式都基本相同:地址碼、功能碼、數據區和錯誤校驗碼。
2.錯誤校驗
冗餘循環碼(CRC)包含2個字節,即16位二進制。CRC碼由發送設備計算,放置於發送信息的尾部。接收信息的設備再從新計算接收到信息的 CRC碼,比較計算獲得的CRC碼是否與接收到的相符,若是二者不相符,則代表出錯。
CRC碼的計算方法是,先預置16位寄存器全爲1。再逐步把每8位數據信息進行處理。在進行CRC碼計算時只用8位數據位,起始位及中止位,若有奇偶校驗位的話也包括奇偶校驗位,都不參與CRC碼計算。
在計算CRC碼時,8位數據與寄存器的數據相異或,獲得的結果向低位移一字節,用0填補最高位。再檢查最低位,若是最低位爲1,把寄存器的內容與預置數相異或,若是最低位爲0,不進行異或運算。
這個過程一直重複8次。第8次移位後,下一個8位再與如今寄存器的內容相相異或,這個過程與以上同樣重複8次。當全部的數據信息處理完後,最後寄存器的內容即爲CRC碼值。CRC碼中的數據發送、接收時低字節在前。
計算CRC碼的步驟爲:
3.功能碼03,讀取點和返回值:
儀表採用Modbus RTU通信規約,利用通信命令,能夠進行讀取點(「保持寄存器」) 或返回值(「輸入寄存器」 )的操做。保持和輸入寄存器都是16位(2字節)值,而且高位在前。這樣用於儀表的讀取點和返回值都是2字節。一次最多可讀取寄存器數是60。因爲一些可編程控制器不用功能碼03,因此功能碼03被用做讀取點和返回值。從機響應的命令格式是從機地址、功能碼、數據區及CRC碼。數據區中的寄存器數據都是每兩個字節高字節在前。
4.功能碼06,單點保存
主機利用這條命令把單點數據保存到儀表的存儲器。從機也用這個功能碼向主機返送信息。
2、編程舉例
下面是一個用VC編寫的ModBus RTU通信的例子
(一)、通信口設置
DCB dcb; hCom=CreateFile("COM1", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hCom==INVALID_HANDLE_VALUE) { MessageBox("createfile error,error"); }
BOOL error=SetupComm(hCom,1024,1024);
if(!error) MessageBox("setupcomm error");
error=GetCommState(hCom,&dcb);
if(!error) MessageBox("getcommstate,error");
dcb.BaudRate=2400; dcb.ByteSize=8; dcb.Parity=EVENPARITY;//NOPARITY; dcb.StopBits=ONESTOPBIT; error=SetCommState(hCom,&dcb);
(二)、CRC校驗碼計算
UINT crc void calccrc(BYTE crcbuf) { BYTE i; crc=crc ^ crcbuf; for(i=0;i<8;i++) { BYTE TT; TT=crc&1; crc=crc>>1; crc=crc&0x7fff; if (TT==1) crc=crc^0xa001; crc=crc&0xffff; } }
(三)、數據發送
zxaddr=11;//讀取地址爲11的巡檢表數據 zxnum=10;//讀取十個通道的數據 writebuf2[0]=zxaddr; writebuf2[1]=3; writebuf2[2]=0; writebuf2[3]=0; writebuf2[4]=0; writebuf2[5]=zxnum; crc=0xffff; calccrc(writebuf2[0]); calccrc(writebuf2[1]); calccrc(writebuf2[2]); calccrc(writebuf2[3]); calccrc(writebuf2[4]); calccrc(writebuf2[5]); writebuf2[6]=crc & 0xff; writebuf2[7]=crc/0x100; WriteFile(hCom,writebuf2,8,&comnum,NULL);
(四)、數據讀取
ReadFile(hCom,writebuf,5+zxnum*2,&comnum,NULL);//讀取zxnum個通道數據
可增長錯誤處理程序,如地址碼錯誤、CRC碼錯誤判斷、通信故障處理等。
(五)、CRC簡單函數
unsigned short CRC16(puchMsg, usDataLen) unsigned char *puchMsg ; /* 要進行CRC校驗的消息 */ unsigned short usDataLen ; /* 消息中字節數 */ { unsigned char uchCRCHi = 0xFF ; /* 高CRC字節初始化 */ unsigned char uchCRCLo = 0xFF ; /* 低CRC 字節初始化 */ unsigned uIndex ; /* CRC循環中的索引 */ 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 } ;