CRC校驗(yàn),全名叫做循環(huán)冗余校驗(yàn)碼,是數(shù)據(jù)通訊中最常采用的校驗(yàn)方式。
為了學(xué)習(xí)這個(gè)CRC,在網(wǎng)上找了好多資料,下面這篇文章是最清晰的,整體搬運(yùn)過來:(http://blog.163.com/du_minchao@126/blog/static/107495394201075114028606/)
一、基本原理
CRC檢驗(yàn)原理實(shí)際上就是在一個(gè)p位二進(jìn)制數(shù)據(jù)序列之后附加一個(gè)r位二進(jìn)制檢驗(yàn)碼(序列),從而構(gòu)成一個(gè)總長(zhǎng)為n=p+r位的二進(jìn)制序列;附加在數(shù)據(jù)序列之后的這個(gè)檢驗(yàn)碼與數(shù)據(jù)序列的內(nèi)容之間存在著某種特定的關(guān)系。如果因干擾等原因使數(shù)據(jù)序列中的某一位或某些位發(fā)生錯(cuò)誤,這種特定關(guān)系就會(huì)被破壞。因此,通過檢查這一關(guān)系,就可以實(shí)現(xiàn)對(duì)數(shù)據(jù)正確性的檢驗(yàn)。
二、幾個(gè)基本概念1、幀檢驗(yàn)序列FCS(Frame Check Sequence):為了進(jìn)行差錯(cuò)檢驗(yàn)而添加的冗余碼。
2、多項(xiàng)式模2運(yùn)行:實(shí)際上是按位異或(Exclusive
OR)運(yùn)算,即相同為0,相異為1,也就是不考慮進(jìn)位、借位的二進(jìn)制加減運(yùn)算。如:10011011 + 11001010 = 01010001。3、生成多項(xiàng)式(generator
polynomial):當(dāng)進(jìn)行CRC檢驗(yàn)時(shí),發(fā)送方與接收方需要事先約定一個(gè)除數(shù),即生成多項(xiàng)式,一般記作G(x)。生成多項(xiàng)式的最高位與最低位必須是1。常用的CRC碼的生成多項(xiàng)式有:CRC8=X8+X5+X4+1
CRC-CCITT=X16+X12+X5+1
CRC16=X16+X15+X5+1
CRC12=X12+X11+X3+X2+1
CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1
每一個(gè)生成多項(xiàng)式都可以與一個(gè)代碼相對(duì)應(yīng),如CRC8對(duì)應(yīng)代碼:100110001。
三、CRC檢驗(yàn)碼的計(jì)算
設(shè)信息字段為K位,校驗(yàn)字段為R位,則碼字長(zhǎng)度為N(N=K+R)。設(shè)雙方事先約定了一個(gè)R次多項(xiàng)式g(x),則CRC碼:
V(x)=A(x)g(x)=xRm(x)+r(x)
其中: m(x)為K次信息多項(xiàng)式, r(x)為R-1次校驗(yàn)多項(xiàng)式。
這里r(x)對(duì)應(yīng)的代碼即為冗余碼,加在原信息字段后即形成CRC碼。
r(x)的計(jì)算方法為:在K位信息字段的后面添加R個(gè)0,再除以g(x)對(duì)應(yīng)的代碼序列,得到的余數(shù)即為r(x)對(duì)應(yīng)的代碼(應(yīng)為R-1位;若不足,而在高位補(bǔ)0)。
計(jì)算示例
設(shè)需要發(fā)送的信息為M = 1010001101,產(chǎn)生多項(xiàng)式對(duì)應(yīng)的代碼為P =
110101,R=5。在M后加5個(gè)0,然后對(duì)P做模2除法運(yùn)算,得余數(shù)r(x)對(duì)應(yīng)的代碼:01110。故實(shí)際需要發(fā)送的數(shù)據(jù)是101000110101110。這里寫圖片描述四、錯(cuò)誤檢測(cè)
當(dāng)接收方收到數(shù)據(jù)后,用收到的數(shù)據(jù)對(duì)P(事先約定的)進(jìn)行模2除法,若余數(shù)為0,則認(rèn)為數(shù)據(jù)傳輸無差錯(cuò);若余數(shù)不為0,則認(rèn)為數(shù)據(jù)傳輸出現(xiàn)了錯(cuò)誤,由于不知道錯(cuò)誤發(fā)生在什么地方,因而不能進(jìn)行自動(dòng)糾正,一般的做法是丟棄接收的數(shù)據(jù)。
五、幾點(diǎn)說明:1、CRC是一種常用的檢錯(cuò)碼,并不能用于自動(dòng)糾錯(cuò)。
2、只要經(jīng)過嚴(yán)格的挑選,并使用位數(shù)足夠多的除數(shù) P,那么出現(xiàn)檢測(cè)不到的差錯(cuò)的概率就很小很小。
3、僅用循環(huán)冗余檢驗(yàn) CRC 差錯(cuò)檢測(cè)技術(shù)只能做到無差錯(cuò)接受(只是非常近似的認(rèn)為是無差錯(cuò)的),并不能保證可靠傳輸。
以上是在網(wǎng)上看到的資料,而我們的項(xiàng)目中的需求是:采用16位的CRC校驗(yàn)碼,并采用CRC-CCITT多項(xiàng)式X16+X12+X5 +1。也就是在上文中沒有提到的 CRC-CCITT ,
CRC在線校驗(yàn)地址:https://www.lammertbies.nl/comm/info/crc-calculation.html
具體的代碼如下:
#import <Foundation/Foundation.h>
@interface NSData (CRC16)
//Nsdata CRC 校驗(yàn) ,返回data
-(NSData*)crc16 ;
//Nsdata 轉(zhuǎn)化成 hex字符串
- (NSString *)hexadecimalString;
@end
#import "NSData+CRC16.h"
@implementation NSData (CRC16)
- (NSData*)crc16 {
const uint8_t *byte = (const uint8_t *)self.bytes;
uint16_t length = (uint16_t)self.length;
uint16_t res = gen_crc16(byte, length);
NSData *val = [NSData dataWithBytes:&res length:sizeof(res)];
return val;
}
#define PLOY 0X1021
uint16_t gen_crc16(const uint8_t *data, uint16_t size) {
uint16_t crc = 0;
uint8_t i;
for (; size > 0; size--) {
crc = crc ^ (*data++ <<8);
for (i = 0; i < 8; i++) {
if (crc & 0X8000) {
crc = (crc << 1) ^ PLOY;
}else {
crc <<= 1;
}
}
crc &= 0XFFFF;
}
return crc;
}
- (NSString *)hexadecimalString
{
const unsigned char *dataBuffer = (const unsigned char *)[self bytes];
if (!dataBuffer)
{
return [NSString string];
}
NSUInteger dataLength = [self length];
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < dataLength; ++i)
{
[hexString appendFormat:@"%02x", (unsigned int)dataBuffer[i]];
}
return [NSString stringWithString:hexString];
}
@end