CRC校验解读
crc.c[0] = crc.c[1]^crctableh[t];
crc.c[1] = crctablel[t];
n--;
buf++;
}
return ( crc.x );
}
表面上看起来,函数crc1比crc0的源代码还长一些。但是编译后,函数crc1的目标代码实际为44个字节,加上表格占用的512个字节,一共使用了556个字节,比函数crc0反而节约了24个字节。这两个函数的运行对比情况见表一。
计算CRC校验时,最常用的计算方式有三种:查表、计算、查表+计算。一般来说,查表法最快,但是需要较大的空间存放表格;计算法最慢,但是代码最简洁、占用空间最小;而在既要求速度,空间又比较紧张时常用查表+计算法。
下面我们分别就这三种方法进行讨论和比较。这里以使用广泛的51单片机为例,分别用查表、计算、查表+计算三种方法计算1021多项式(CRC-ITU)校验。原始程序都是在网上或杂志上经常能见到的,相信大家也比较熟悉了,甚至就是正在使用或已经使用过的程序。
crc ^= crc_ta[da^(*ptr&0x0f)];/* CRC的高4位和本字节的后半字节相加后查表*/
/*计算CRC,然后再加上上一次CRC的余数*/
ptБайду номын сангаас++;
}
return crc;
}
程序优化策略:上面程序都只是给出了通用算法,并没有考虑到51单片机的特点。我们知道,51单片机是8位单片机,使用的变量类型也是8位的。如果在程序中使用8位的变量速度是最快的,比使用16位的变量代码短、效率高。在上面的程序中都使用了大量整型数类型(16位)的表格和整型数类型的变量,特别是关键的变量。如果我们不使用整型类型的表格和变量,而使用字节类型的表格和变量,就能够使程序的性能得到优化。基于这种思路,我们将原来整型的表格拆分为两个字节型(8位)的表格,即将原来表格的高低字节分别拆开,每个表格还是256个单元,这样表格的大小和顺序都没有变;原来使用16位变量计算的地方,改用8位变量计算。
nLength--;
pData++;
}
return CRC16;
}
编译后,函数crc0的代码为68字节,加上表格占用的512字节,一共使用了580个字节的代码空间。
下面是常见的计算法的程序:
unsigned int crc2(unsigned char *ptr,unsigned char count)
三种常用的CRC16校验算法的C51程序的优化2009-10-10 09:34:17|分类:技术知识|标签:|字号大
CRC校验又称为循环冗余校验,是数据通讯中常用的一种校验算法。它可以有效的判别出数据在传输过程中是否发生了错误,从而保障了传输的数据可靠性。
CRC校验有多种方式,如:CRC8、CRC16、CRC32等等。在实际使用中,我们经常使用CRC16校验。CRC16校验也有多种,如:1005多项式、1021多项式(CRC-ITU)等。在这里我们不讨论CRC算法是怎样产生的,而是重点落在几种算法的C51程序的优化上。
{
unsigned int crc =0;
unsigned char i;
while(count-- >0)
{
crc = ( crc^(((unsigned int)*ptr)<<8));
for(i=0;i<8;i++)
{
if(crc&0x8000) crc= ((crc<<1)^0x1021);
else crc <<= 1;
};
unsigned int crc1(unsigned char *buf,unsigned char n)
{
unsigned char t;
union{
unsigned char c[2];
unsigned int x;
}data crc;
crc.x = 0;
while(n !=0)
{
t = crc.c[0]^*buf;
}
ptr++;
}
return crc;
}
下面是常见的一种查表+计算的方法:
unsigned int crc4(unsigned char *ptr, unsigned char len) {
unsigned int crc;
unsigned char da;
code unsigned int crc_ta[16]={ /* CRC余式表*/
修改后的查表程序如下(省略了表格的内容):
code unsigned char crctableh[256]={
0x00,0x10,0x20,0x30,... 0x0E,0x1E,
};
code unsigned char crctablel[256]={
0x00,0x21,0x42,0x63,... 0xD1,0xF0,
编译平台采用Keil C51 7.0,使用小内存模式,编译器默认的优化方式。
常用的查表法程序如下,这是网上经常能够看到的程序范例。因为篇幅关系,省略了大部分表格的内容。
code unsigned int Crc1021Table[256] = {
0x0000, 0x1021, 0x2042, 0x3063,... 0x1ef0
crc <<=4; /* CRC右移4位,相当于取CRC的低12位)*/
crc ^= crc_ta[da^(*ptr/16)]; /* CRC的高4位和本字节的前半字节相加后查表*/
/*计算CRC,然后加上上一次CRC的余数*/
da = ((crc/256))/16; /*暂存CRC的高4位*/
crc <<=4; /* CRC右移4位,相当于CRC的低12位)*/
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
};
crc=0;
while(len-->0) {
da = ((crc/256))/16; /*暂存CRC的高四位*/
};
unsigned int crc0(unsigned char *pData, unsigned char nLength)
{
unsigned int CRC16 = 0;
while(nLength>0)
{
CRC16 = (CRC16 << 8 ) ^ Crc1021Table[((CRC16>>8) ^ *pData) & 0xFF];