(內文如有算錯請多包涵)
為了寫實驗室的通訊協定(Modbus),學長要求要寫CRC,還特別指定CRC16的CCITT,聽都沒聽過,所以就先來了解一下CRC是什麼好了。
以我這種外行人來說,我只要知道它的規則和大致的原理就好~ CRC簡單來說就是把一筆資料加上一定數量的0,讓資料可以被規定的CRC函數除,留下一個餘數就是CRC了。
CRC16 CCITT的函數就是 X^16+X^12+X^5+1; 那麼用二進位看它的係數可以看成 17'b10001000000100001(當成除數); 啊如果一筆資料進來要怎麼辦呢?
以正常來說,假設一筆資料是 8'b11111111; 那麼就會補跟函數最高次方一樣多的0,CCITT的是16次方,所以資料後面要加上16個0。
就變成了 24'b111111110000000000000000。為什麼要加上16個0呢?因為除數是17位的話,餘數最長就是16位。來看看要怎麼算好了!
這個除法不是一般的除法,一般的除法是用減的,可是這邊是用XOR來做運算。 XOR就是 11 = 0,00 = 0,01=1,10=1。
111111110000000000000000 被除數(資料)
10001000000100000 除數
================== 做XOR運算(上下)
01110111000100000 得到了餘數,扣去MSB不看,只剩下十六位,除數有十七位呢!所以在抓一個0下來補吧。
11101110001000000 加一個0之後又是十七位了,又可以跟除數做運算了。%%% 如果第十六位也是0的話,就要抓兩個0哦~以此類推%%%
10001000000100000 除數
================== 做XOR運算(上下)
01100110001100000 這裡又得到一個餘數,第十七位還是0,那就繼續抓0做下去。理論上這樣做下去,做到被除數(原本有24位)只剩下17位的話,再跟除數做一次運算得到的餘數,那就是我們要的CRC碼了。
人家的文章也寫得不錯,奇偶校檢位也是一種很簡單的CRC,它的函數就是X+1。所以除數就是2'b11。資料如果是8'b10110101
運算結果應該是 101101010
11
011
11
00010
11
000011
11
000000010
11
1 結果是1 所以有奇數個1在資料裡。
當然理論上是這樣啦,實際上是什麼??? 我查了很久,終於在一個有CRC-CCITT的device中的datasheet找到真正的算法(或是演算規則)
第一步:先假設我們要算的CRC = 16'hFFFF ; 然後我們要的除數是16'h1021;(CCITT的函數)
第二步:先把資料的後端加上8個0,讓資料變成16位,然後把CRC跟資料做XOR,會得到一組新的CRC;
第三步:如果上一步新的CRC如果最高位是1(也就是data[15]是1),那就把資料先左移一位,然後跟除數16'h1021做XOR,得到的結果再跟16'hFFFF做AND。
否則,就直接左移一位,再跟16'hFFFF做AND。如此這個規則重複"八次"之後,就會把一個byte(8個bit)的資料都跟除數演算過了。得到的結果就是CRC碼嘍。
如果有很多個byte怎麼辦? 第三步的結果只會得到一個byte的CRC,那就就把第三步得到的CRC帶回第一步去,所以第一步的CRC不在是FFFF了,而是你算出第一筆資料的CRC,
然後第二步再放新的資料進來跟第一步新的CRC做XOR,接著再做第三步。就是這樣!
