CRC校验.docx
- 文档编号:2141693
- 上传时间:2022-10-27
- 格式:DOCX
- 页数:10
- 大小:19.30KB
CRC校验.docx
《CRC校验.docx》由会员分享,可在线阅读,更多相关《CRC校验.docx(10页珍藏版)》请在冰豆网上搜索。
CRC校验
三种常用的CRC16校验算法的C51程序的优化2009-10-1009:
34:
17|分类:
技术知识|标签:
|字号大
CRC校验又称为循环冗余校验,是数据通讯中常用的一种校验算法。
它可以有效的判别出数据在传输过程中是否发生了错误,从而保障了传输的数据可靠性。
CRC校验有多种方式,如:
CRC8、CRC16、CRC32等等。
在实际使用中,我们经常使用CRC16校验。
CRC16校验也有多种,如:
1005多项式、1021多项式(CRC-ITU)等。
在这里我们不讨论CRC算法是怎样产生的,而是重点落在几种算法的C51程序的优化上。
计算CRC校验时,最常用的计算方式有三种:
查表、计算、查表+计算。
一般来说,查表法最快,但是需要较大的空间存放表格;计算法最慢,但是代码最简洁、占用空间最小;而在既要求速度,空间又比较紧张时常用查表+计算法。
下面我们分别就这三种方法进行讨论和比较。
这里以使用广泛的51单片机为例,分别用查表、计算、查表+计算三种方法计算1021多项式(CRC-ITU)校验。
原始程序都是在网上或杂志上经常能见到的,相信大家也比较熟悉了,甚至就是正在使用或已经使用过的程序。
编译平台采用KeilC517.0,使用小内存模式,编译器默认的优化方式。
常用的查表法程序如下,这是网上经常能够看到的程序范例。
因为篇幅关系,省略了大部分表格的内容。
codeunsignedintCrc1021Table[256]={
0x0000,0x1021,0x2042,0x3063,...0x1ef0
};
unsignedintcrc0(unsignedchar*pData,unsignedcharnLength)
{
unsignedintCRC16=0;
while(nLength>0)
{
CRC16=(CRC16<<8)^Crc1021Table[((CRC16>>8)^*pData)&0xFF];
nLength--;
pData++;
}
returnCRC16;
}
编译后,函数crc0的代码为68字节,加上表格占用的512字节,一共使用了580个字节的代码空间。
下面是常见的计算法的程序:
unsignedintcrc2(unsignedchar*ptr,unsignedcharcount)
{
unsignedintcrc=0;
unsignedchari;
while(count-->0)
{
crc=(crc^(((unsignedint)*ptr)<<8));
for(i=0;i<8;i++)
{
if(crc&0x8000)crc=((crc<<1)^0x1021);
elsecrc<<=1;
}
ptr++;
}
returncrc;
}
下面是常见的一种查表+计算的方法:
unsignedintcrc4(unsignedchar*ptr,unsignedcharlen){
unsignedintcrc;
unsignedcharda;
codeunsignedintcrc_ta[16]={/*CRC余式表*/
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的高四位*/
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位)*/
crc^=crc_ta[da^(*ptr&0x0f)];/*CRC的高4位和本字节的后半字节相加后查表*/
/*计算CRC,然后再加上上一次CRC的余数*/
ptr++;
}
returncrc;
}
程序优化策略:
上面程序都只是给出了通用算法,并没有考虑到51单片机的特点。
我们知道,51单片机是8位单片机,使用的变量类型也是8位的。
如果在程序中使用8位的变量速度是最快的,比使用16位的变量代码短、效率高。
在上面的程序中都使用了大量整型数类型(16位)的表格和整型数类型的变量,特别是关键的变量。
如果我们不使用整型类型的表格和变量,而使用字节类型的表格和变量,就能够使程序的性能得到优化。
基于这种思路,我们将原来整型的表格拆分为两个字节型(8位)的表格,即将原来表格的高低字节分别拆开,每个表格还是256个单元,这样表格的大小和顺序都没有变;原来使用16位变量计算的地方,改用8位变量计算。
修改后的查表程序如下(省略了表格的内容):
codeunsignedcharcrctableh[256]={
0x00,0x10,0x20,0x30,...0x0E,0x1E,
};
codeunsignedcharcrctablel[256]={
0x00,0x21,0x42,0x63,...0xD1,0xF0,
};
unsignedintcrc1(unsignedchar*buf,unsignedcharn)
{
unsignedchart;
union{
unsignedcharc[2];
unsignedintx;
}datacrc;
crc.x=0;
while(n!
=0)
{
t=crc.c[0]^*buf;
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个字节。
这两个函数的运行对比情况见表一。
我们采用和上面相同的优化方法来优化计算法的程序,优化后的计算法程序为:
unsignedintcrc3(unsignedchar*ptr,unsignedcharcount)
{
dataunsignedchari;
union{
unsignedcharc[2];
unsignedintx;
}datacrc;
crc.x=0;
while(count!
=0)
{
crc.c[0]^=*ptr;
for(i=8;i>0;i--)
{
if(crc.c[0]&0x70)crc.x=(crc.x<<1)&0x1021;
elsecrc.x=crc.x<<1;
}
ptr++;
count--;
}
returncrc.x;
}
编译后函数crc2的代码长度为76,函数crc3的代码长度为68,变化不是太大,但是执行效率是很不一样的,具体差别见后面的表一。
优化后的查表+计算法的程序为:
unsignedintcrc5(unsignedchar*ptr,unsignedcharlen)
{
codeunsignedcharcrch[16]={/*CRC余式表*/
0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,
0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
};
codeunsignedcharcrcl[16]={/*CRC余式表*/
0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,
0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,
};
union{
unsignedcharc[2];
unsignedintx;
}datacrc;
unsignedchart;
crc.x=0;
while(len!
=0){
t=(crc.c[0]>>4)^(*ptr>>4);
crc.x<<=4;
crc.c[0]^=crch[t];
crc.c[1]^=crcl[t];
t=(crc.c[0]>>4)^(*ptr&0x0F);
crc.x<<=4;
crc.c[0]^=crch[t];
crc.c[1]^=crcl[t];
ptr++;
len--;
}
returncrc.x;
}
优化前后的代码长度分别为175字节和146字节(包括了32字节的表格空间)。
代码测试:
仅代码长度变短是不够的,衡量优化后的程序一个重要的标准是看优化前后两个函数执行相同的计算量使用的时间,或者说执行的效率是否提高了。
如果优化后的函数需要时间少,就说明我们优化后的函数确实提高了效率,否则就是反而降低了程序的效率,优化失败。
我在KeilC51下编写了一个测试程序,在程序中调用了上面的六个函数,共同计算一个长度为200字节的CRC校验,并记录下每个函数使用的时间。
测试方法为:
使用KeilC51的软件仿真功能(采用带计时功能的硬件仿真器也可以),在每个函数上加上断点,记录下执行到每个断点的时间,然后前后相减就得出每个函数的执行时间。
仿真时使用的单片机型号为AT89C51,晶体频率为12MHz。
测试文件的源代码为:
xdataunsignedcharbuf[200];
unsignedchari;
unsignedintcrc;
externunsignedintcrc0(unsignedchar*,unsignedchar);
externunsignedintcrc1(unsignedchar*,unsignedchar);
externunsignedintcrc2(unsignedchar*,unsignedchar);
externunsignedintcrc3(unsignedchar*,unsignedchar);
externunsignedintcrc4(unsignedchar*,unsignedchar);
externunsignedintcrc5(unsignedchar*,unsignedchar);
voidmain(void)
{
for(i=0;i<200;i++)
buf[i]=i+1;
crc=crc0(buf,200);
crc=crc1(buf,200);
crc=crc2(buf,200);
crc=crc3(buf,200);
crc=crc4(buf,200);
crc=crc5(buf,200);
i=0;
}
测试结果见表一:
函数
代码长度(字节)
执行时间(微秒)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- CRC 校验