MODBUS通訊協議及編程

一、Modbus 協議簡介

 

 Modbus 協議是應用於電子控制器上的一種通用語言。通過此協議,控制器相互之間、控制器經由網絡(例如以太網)和其它設備之間可以通信。它已經成爲一通用工業標準。有了它,不同廠商生產的控制設備可以連成工業網絡,進行集中監控。

 

 此協議定義了一個控制器能認識使用的消息結構,而不管它們是經過何種網絡進行通信的。它描述了一控制器請求訪問其它設備的過程,如果迴應來自其它設備的請求,以及怎樣偵測錯誤並記錄。它制定了消息域格局和內容的公共格式。

 

 當在一Modbus網絡上通信時,此協議決定了每個控制器須要知道它們的設備地址,識別按地址發來的消息,決定要產生何種行動。如果需要回應,控制器將生成反饋信息並用Modbus協議發出。在其它網絡上,包含了Modbus協議的消息轉換爲在此網絡上使用的幀或包結構。這種轉換也擴展了根據具體的網絡解決節地址、路由路徑及錯誤檢測的方法。

1、在Modbus網絡上轉輸

 標準的Modbus口是使用一RS-232C兼容串行接口,它定義了連接口的針腳、電纜、信號位、傳輸波特率、奇偶校驗。控制器能直接或經由Modem組網。

 

 控制器通信使用主—從技術,即僅一設備(主設備)能初始化傳輸(查詢)。其它設備(從設備)根據主設備查詢提供的數據作出相應反應。典型的主設備:主機和可編程儀表。典型的從設備:可編程控制器。

 

 主設備可單獨和從設備通信,也能以廣播方式和所有從設備通信。如果單獨通信,從設備返回一消息作爲迴應,如果是以廣播方式查詢的,則不作任何迴應。Modbus協議建立了主設備查詢的格式:設備(或廣播)地址、功能代碼、所有要發送的數據、一錯誤檢測域。

 

 從設備迴應消息也由Modbus協議構成,包括確認要行動的域、任何要返回的數據、和一錯誤檢測域。如果在消息接收過程中發生一錯誤,或從設備不能執行其命令,從設備將建立一錯誤消息並把它作爲迴應發送出去。

2、在其它類型網絡上轉輸

 在其它網絡上,控制器使用對等技術通信,故任何控制都能初始和其它控制器的通信。這樣在單獨的通信過程中,控制器既可作爲主設備也可作爲從設備。提供的多個內部通道可允許同時發生的傳輸進程。

 

 在消息位,Modbus協議仍提供了主—從原則,儘管網絡通信方法是“對等”。如果一控制器發送一消息,它只是作爲主設備,並期望從從設備得到迴應。同樣,當控制器接收到一消息,它將建立一從設備迴應格式並返回給發送的控制器。

3、查詢—迴應週期

(1)查詢

 查詢消息中的功能代碼告之被選中的從設備要執行何種功能。數據段包含了從設備要執行功能的任何附加信息。例如功能代碼03是要求從設備讀保持寄存器並返回它們的內容。數據段必須包含要告之從設備的信息:從何寄存器開始讀及要讀的寄存器數量。錯誤檢測域爲從設備提供了一種驗證消息內容是否正確的方法。

(2)迴應

 如果從設備產生一正常的迴應,在迴應消息中的功能代碼是在查詢消息中的功能代碼的迴應。數據段包括了從設備收集的數據:象寄存器值或狀態。如果有錯誤發生,功能代碼將被修改以用於指出迴應消息是錯誤的,同時數據段包含了描述此錯誤信息的代碼。錯誤檢測域允許主設備確認消息內容是否可用。

二、兩種傳輸方式

 控制器能設置爲兩種傳輸模式(ASCII或RTU)中的任何一種在標準的Modbus網絡通信。用戶選擇想要的模式,包括串口通信參數(波特率、校驗方式等),在配置每個控制器的時候,在一個Modbus網絡上的所有設備都必須選擇相同的傳輸模式和串口參數。

ASCII模式

:

地址

功能代碼

數據數量

數據1

...

數據n

LRC高字節

LRC低字節

回車

換行

RTU模式

地址

功能代碼

數據數量

數據1

...

數據n

CRC低字節

CRC高字節

 所選的ASCII或RTU方式僅適用於標準的Modbus網絡,它定義了在這些網絡上連續傳輸的消息段的每一位,以及決定怎樣將信息打包成消息域和如何解碼。

 在其它網絡上(象MAP和Modbus Plus)Modbus消息被轉成與串行傳輸無關的幀。

1、ASCII模式

 當控制器設爲在Modbus網絡上以ASCII(美國標準信息交換代碼)模式通信,在消息中的每個8Bit字節都作爲兩個ASCII字符發送。這種方式的主要優點是字符發送的時間間隔可達到1秒而不產生錯誤。

 代碼系統

·  十六進制,ASCII字符0...9,A...F

·  消息中的每個ASCII字符都是一個十六進制字符組成

每個字節的位

·  1個起始位

·  7個數據位,最小的有效位先發送

·  1個奇偶校驗位,無校驗則無

·  1個停止位(有校驗時),2個Bit(無校驗時)

 錯誤檢測域

·            LRC(縱向冗長檢測)

2、RTU模式

 當控制器設爲在Modbus網絡上以RTU(遠程終端單元)模式通信,在消息中的每個8Bit字節包含兩個4Bit的十六進制字符。這種方式的主要優點是:在同樣的波特率下,可比ASCII方式傳送更多的數據。

代碼系統

·  8位二進制,十六進制數0...9,A...F

·  消息中的每個8位域都是一個兩個十六進制字符組成

·  每個字節的位

·  1個起始位

·  8個數據位,最小的有效位先發送

·  1個奇偶校驗位,無校驗則無

·  1個停止位(有校驗時),2個Bit(無校驗時)

錯誤檢測域

·  CRC(循環冗長檢測)

三、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 ASCII消息幀

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

圖3 RTU消息幀

3、地址域

 消息幀的地址域包含兩個字符(ASCII)或8Bit(RTU)。可能的從設備地址是0...247 (十進制)。單個設備的地址範圍是1...247。主設備通過將要聯絡的從設備的地址放入消息中的地址域來選通從設備。當從設備發送迴應消息時,它把自己的地址放入迴應的地址域中,以便主設備知道是哪一個設備作出迴應。

 

 地址0是用作廣播地址,以使所有的從設備都能認識。當Modbus協議用於更高水準的網絡,廣播可能不允許或以其它方式代替。

4、如何處理功能域

 消息幀中的功能代碼域包含了兩個字符(ASCII)或8Bits(RTU)。可能的代碼範圍是十進制的1...255。當然,有些代碼是適用於所有控制器,有此是應用於某種控制器,還有些保留以備後用。

 

 當消息從主設備發往從設備時,功能代碼域將告之從設備需要執行哪些行爲。例如去讀取輸入的開關狀態,讀一組寄存器的數據內容,讀從設備的診斷狀態,允許調入、記錄、校驗在從設備中的程序等。

 

 當從設備迴應時,它使用功能代碼域來指示是正常回應(無誤)還是有某種錯誤發生(稱作異議迴應)。對正常回應,從設備僅迴應相應的功能代碼。對異議迴應,從設備返回一等同於正常代碼的代碼,但最重要的位置爲邏輯1。

 例如:一從主設備發往從設備的消息要求讀一組保持寄存器,將產生如下功能代碼:

0 0 0 0 0 0 1 1 (十六進制03H)

 對正常回應,從設備僅迴應同樣的功能代碼。對異議迴應,它返回:

1 0 0 0 0 0 1 1 (十六進制83H)

 除功能代碼因異議錯誤作了修改外,從設備將一獨特的代碼放到迴應消息的數據域中,這能告訴主設備發生了什麼錯誤。

 主設備應用程序得到異議的迴應後,典型的處理過程是重發消息,或者診斷髮給從設備的消息並報告給操作員。

5、數據域

 數據域是由兩個十六進制數集合構成的,範圍00...FF。根據網絡傳輸模式,這可以是由一對ASCII字符組成或由一RTU字符組成。

 從主設備發給從設備消息的數據域包含附加的信息:從設備必須用於進行執行由功能代碼所定義的所爲。這包括了象不連續的寄存器地址,要處理項的數目,域中實際數據字節數。

 例如,如果主設備需要從設備讀取一組保持寄存器(功能代碼03),數據域指定了起始寄存器以及要讀的寄存器數量。如果主設備寫一組從設備的寄存器(功能代碼10十六進制),數據域則指明瞭要寫的起始寄存器以及要寫的寄存器數量,數據域的數據字節數,要寫入寄存器的數據。

 如果沒有錯誤發生,從從設備返回的數據域包含請求的數據。如果有錯誤發生,此域包含一異議代碼,主設備應用程序可以用來判斷採取下一步行動。

 在某種消息中數據域可以是不存在的(0長度)。例如,主設備要求從設備迴應通信事件記錄(功能代碼0B十六進制),從設備不需任何附加的信息。

6、錯誤檢測域

 標準的Modbus網絡有兩種錯誤檢測方法。錯誤檢測域的內容視所選的檢測方法而定。

ASCII

 當選用ASCII模式作字符幀,錯誤檢測域包含兩個ASCII字符。這是使用LRC(縱向冗長檢測)方法對消息內容計算得出的,不包括開始的冒號符及回車換行符。LRC字符附加在回車換行符前面。

RTU

 當選用RTU模式作字符幀,錯誤檢測域包含一16Bits值(用兩個8位的字符來實現)。錯誤檢測域的內容是通過對消息內容進行循環冗長檢測方法得出的。CRC域附加在消息的最後,添加時先是低字節然後是高字節。故CRC的高位字節是發送消息的最後一個字節。

7、字符的連續傳輸

 當消息在標準的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)

四、錯誤檢測方法

 標準的Modbus串行網絡採用兩種錯誤檢測方法。奇偶校驗對每個字符都可用,幀檢測(LRC或CRC)應用於整個消息。它們都是在消息發送前由主設備產生的,從設備在接收過程中檢測每個字符和整個消息幀。

 用戶要給主設備配置一預先定義的超時時間間隔,這個時間間隔要足夠長,以使任何從設備都能作爲正常反應。如果從設備測到一傳輸錯誤,消息將不會接收,也不會向主設備作出迴應。這樣超時事件將觸發主設備來處理錯誤。發往不存在的從設備的地址也會產生超時。

1、奇偶校驗

 用戶可以配置控制器是奇或偶校驗,或無校驗。這將決定了每個字符中的奇偶校驗位是如何設置的。

 如果指定了奇或偶校驗,“1”的位數將算到每個字符的位數中(ASCII模式7個數據位,RTU中8個數據位)。例如RTU字符幀中包含以下8個數據位:

1 1 0 0 0 1 0 1

 整個“1”的數目是4個。如果便用了偶校驗,幀的奇偶校驗位將是0,便得整個“1”的個數仍是4個。如果便用了奇校驗,幀的奇偶校驗位將是1,便得整個“1”的個數是5個。

 如果沒有指定奇偶校驗位,傳輸時就沒有校驗位,也不進行校驗檢測。代替一附加的停止位填充至要傳輸的字符幀中。

 

2、LRC檢測

 

 使用ASCII模式,消息包括了一基於LRC方法的錯誤檢測域。LRC域檢測了消息域中除開始的冒號及結束的回車換行號外的內容。

 LRC域是一個包含一個8位二進制值的字節。LRC值由傳輸設備來計算並放到消息幀中,接收設備在接收消息的過程中計算LRC,並將它和接收到消息中LRC域中的值比較,如果兩值不等,說明有錯誤。

 LRC方法是將消息中的8Bit的字節連續累加,丟棄了進位。

 LRC簡單函數如下:

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))) ;

}

3、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協議簡要介紹如下:

一、通訊協議

(一)、通訊傳送方式:
   通訊傳送分爲獨立的信息頭,和發送的編碼數據。以下的通訊傳送方式定義也與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碼的步驟爲:

·  預置16位寄存器爲十六進制FFFF(即全爲1)。稱此寄存器爲CRC寄存器;

·  把第一個8位數據與16位CRC寄存器的低位相異或,把結果放於CRC寄存器;

·  把寄存器的內容右移一位(朝低位),用0填補最高位,檢查最低位;

·  如果最低位爲0:重複第3步(再次移位); 如果最低位爲1:CRC寄存器與多項式A001(1010 0000 0000 0001)進行異或;

·  重複步驟3和4,直到右移8次,這樣整個8位數據全部進行了處理;

·  重複步驟2到步驟5,進行下一個8位數據的處理;

·  最後得到的CRC寄存器即爲CRC碼。

3.功能碼03,讀取點和返回值:

  儀表採用Modbus RTU通訊規約,利用通訊命令,可以進行讀取點(“保持寄存器”) 或返回值(“輸入寄存器” )的操作。保持和輸入寄存器都是16位(2字節)值,並且高位在前。這樣用於儀表的讀取點和返回值都是2字節。一次最多可讀取寄存器數是60。由於一些可編程控制器不用功能碼03,所以功能碼03被用作讀取點和返回值。從機響應的命令格式是從機地址、功能碼、數據區及CRC碼。數據區中的寄存器數據都是每兩個字節高字節在前。

4.功能碼06,單點保存

  主機利用這條命令把單點數據保存到儀表的存儲器。從機也用這個功能碼向主機返送信息。

二、編程舉例

  下面是一個用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

} ; 

個人分
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章