计算CRC校验码问题

计算CRC校验码问题,第1张

版本

2

子程序

模块_求CRC校验码,

,

公开

参数

要校验的字节组,

字节型,

数组

参数

要校验的字节个数,

整数型

参数

返回CRC码高位,

字节型,

参考

参数

返回CRC码低位,

字节型,

参考

局部变量

循环计数2,

整数型

局部变量

循环计数1,

整数型

局部变量

CRC高位,

字节型

局部变量

CRC低位,

字节型

局部变量

多项式高位,

字节型

局部变量

多项式低位,

字节型

局部变量

保存字高位,

字节型

局部变量

保存字低位,

字节型

CRC高位

255

CRC低位

255

多项式高位

160

多项式低位

1

判断循环首

(循环计数1

要校验的字节个数)

CRC低位

位异或

(CRC低位,

要校验的字节组

[循环计数1

1])

循环计数2

0

判断循环首

(循环计数2

8)

保存字高位

CRC高位

保存字低位

CRC低位

CRC高位

CRC高位

÷

2

CRC低位

CRC低位

÷

2

如果真

(位与

(保存字高位,

1)

1)

CRC低位

位或

(CRC低位,

128)

如果真结束

如果真

(位与

(保存字低位,

1)

1)

CRC高位

位异或

(CRC高位,

多项式高位)

CRC低位

位异或

(CRC低位,

多项式低位)

如果真结束

循环计数2

循环计数2

1

判断循环尾

()

循环计数1

循环计数1

1

判断循环尾

()

返回CRC码高位

CRC高位

返回CRC码低位

CRC低位

返回

()

以上是我用E语言做的CRC校验程序,研究了5天

才做出来的,提供给大家

声明 这是我 年的一个偶然所得 借助了很多朋友和同事的帮助 希望能对在这个领域里面找寻的同行一些帮助

首先用C在SOLARIS上编写一个CRC C文件

使用了SOLARIS上的GCC编译器 编译了CRC C文件 该文件最好放在oracle g主目录下

使用gcc编译器 编译成 位的crc so文件

编译命令是

gcc m fpic o crc o c crc c

gcc shared m o crc so crc o L/usr/sfw/lib/

在数据库中创建lib 命令是

SQL> create or replace library CRC as /opt/oracle g/crc so /

再创建function 命令如下

以下为引用的内容

CREATE OR REPLACE function crc_ (a in varchar )return binary_integeraslanguage Clibrary CRC name call_crc parameters(a string return int);/

以下为引用的内容

SQL> select crc_ ( hello ) from dual

CRC_ ( HELLO )

同使用PERL语言写的CRC 算法程序计算

crc pl hello

结果一致

同理对其他字符串进行了测试 结果一样

lishixinzhi/Article/program/Oracle/201311/17590

CRC算法原理及C语言实现

摘 要 本文从理论上推导出CRC算法实现原理,给出三种分别适应不同计算机或微控制器硬件环境的C语言程序。读者更能根据本算法原理,用不同的语言编写出独特风格更加实用的CRC计算程序。

关键词 CRC 算法 C语言

1 引言

循环冗余码CRC检验技术广泛应用于测控及通信领域。CRC计算可以靠专用的硬件来实现,但是对于低成本的微控制器系统,在没有硬件支持下实现CRC检验,关键的问题就是如何通过软件来完成CRC计算,也就是CRC算法的问题。

这里将提供三种算法,它们稍有不同,一种适用于程序空间十分苛刻但CRC计算速度要求不高的微控制器系统,另一种适用于程序空间较大且CRC计算速度要求较高的计算机或微控制器系统,最后一种是适用于程序空间不太大,且CRC计算速度又不可以太慢的微控制器系统。

2 CRC简介

CRC校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去。在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。

16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(既乘以 )后,再除以一个多项式,最后所得到的余数既是CRC码,如式(2-1)式所示,其中B(X)表示n位的二进制序列数,G(X)为多项式,Q(X)为整数,R(X)是余数(既CRC码)。

(2-1)

求CRC码所采用模2加减运算法则,既是不带进位和借位的按位加减,这种加减运算实际上就是逻辑上的异或运算,加法和减法等价,乘法和除法运算与普通代数式的乘除法运算是一样,符合同样的规律。生成CRC码的多项式如下,其中CRC-16和CRC-CCITT产生16位的CRC码,而CRC-32则产生的是32位的CRC码。本文不讨论32位的CRC算法,有兴趣的朋友可以根据本文的思路自己去推导计算方法。

CRC-16:(美国二进制同步系统中采用)

CRC-CCITT:(由欧洲CCITT推荐)

CRC-32:

接收方将接收到的二进制序列数(包括信息码和CRC码)除以多项式,如果余数为0,则说明传输中无错误发生,否则说明传输有误,关于其原理这里不再多述。用软件计算CRC码时,接收方可以将接收到的信息码求CRC码,比较结果和接收到的CRC码是否相同。

3 按位计算CRC

对于一个二进制序列数可以表示为式(3-1):

(3-1)

求此二进制序列数的CRC码时,先乘以 后(既左移16位),再除以多项式G(X),所得的余数既是所要求的CRC码。如式(3-2)所示:

(3-2)

可以设: (3-3)

其中 为整数, 为16位二进制余数。将式(3-3)代入式(3-2)得:

(3-4)

再设: (3-5)

其中 为整数, 为16位二进制余数,将式(3-5)代入式(3-4),如上类推,最后得到:

(3-6)

根据CRC的定义,很显然,十六位二进制数 既是我们要求的CRC码。

式(3-5)是编程计算CRC的关键,它说明计算本位后的CRC码等于上一位CRC码乘以2后除以多项式,所得的余数再加上本位值除以多项式所得的余数。由此不难理解下面求CRC码的C语言程序。ptr指向发送缓冲区的首字节,len是要发送的总字节数,0x1021与多项式有关。

unsigned int cal_crc(unsigned char ptr, unsigned char len) {

unsigned char i;

unsigned int crc=0;

while(len--!=0) {

for(i=0x80; i!=0; i/=2) {

if((crc&;0x8000)!=0) {crc=2; crc^=0x1021;} / 余式CRC乘以2再求CRC /

else crc=2;

if((ptr&;i)!=0) crc^=0x1021; / 再加上本位的CRC /

}

ptr++;

}

return(crc);

}

按位计算CRC虽然代码简单,所占用的内存比较少,但其最大的缺点就是一位一位地计算会占用很多的处理器处理时间,尤其在高速通讯的场合,这个缺点更是不可容忍。因此下面再介绍一种按字节查表快速计算CRC的方法。

4 按字节计算CRC

不难理解,对于一个二进制序列数可以按字节表示为式(4-1),其中 为一个字节(共8位)。

(4-1)

求此二进制序列数的CRC码时,先乘以 后(既左移16位),再除以多项式G(X),所得的余数既是所要求的CRC码。如式(4-2)所示:

(4-2)

可以设: (4-3)

其中 为整数, 为16位二进制余数。将式(4-3)代入式(4-2)得:

(4-4)

因为:

(4-5)

其中 是 的高八位, 是 的低八位。将式(4-5)代入式(4-4),经整理后得:

(4-6)

再设: (4-7)

其中 为整数, 为16位二进制余数。将式(4-7)代入式(4-6),如上类推,最后得:

(4-8)

很显然,十六位二进制数 既是我们要求的CRC码。

式(4-7)是编写按字节计算CRC程序的关键,它说明计算本字节后的CRC码等于上一字节余式CRC码的低8位左移8位后,再加上上一字节CRC右移8位(也既取高8位)和本字节之和后所求得的CRC码,如果我们把8位二进制序列数的CRC全部计算出来,放如一个表里,采用查表法,可以大大提高计算速度。由此不难理解下面按字节求CRC码的C语言程序。ptr指向发送缓冲区的首字节,len是要发送的总字节数,CRC余式表是按0x11021多项式求出的。

unsigned int cal_crc(unsigned char ptr, unsigned char len) {

unsigned int crc;

unsigned char da;

unsigned int crc_ta[256]={ / CRC余式表 /

0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,

0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,

0x 1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,

0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,

0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,

0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,

0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,

0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,

0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,

0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,

0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 050, 0x3a33, 0x2a12,

0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,

0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,

0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,

0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,

0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,

0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,

0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,

0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,

0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,

0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,

0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,

0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,

0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,

0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,

0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,

0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,

0x4a75, 0x5a54, 0x6a37, 0x7a16, 0f1, 0x1ad0, 0x2ab3, 0x3a92,

0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,

0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,

0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,

0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0

};

crc=0;

while(len--!=0) {

da=(uchar) (crc/256); / 以8位二进制数的形式暂存CRC的高8位 /

crc<<=8; / 左移8位,相当于CRC的低8位乘以 /

crc^=crc_ta[da^ptr]; / 高8位和当前字节相加后再查表求CRC ,再加上以前的CRC /

ptr++;

}

return(crc);

}

很显然,按字节求CRC时,由于采用了查表法,大大提高了计算速度。但对于广泛运用的8位微处理器,代码空间有限,对于要求256个CRC余式表(共512字节的内存)已经显得捉襟见肘了,但CRC的计算速度又不可以太慢,因此再介绍下面一种按半字节求CRC的算法。

5 按半字节计算CRC

同样道理,对于一个二进制序列数可以按字节表示为式(5-1),其中 为半个字节(共4位)。

(5-1)

求此二进制序列数的CRC码时,先乘以 后(既左移16位),再除以多项式G(X),所得的余数既是所要求的CRC码。如式(4-2)所示:

(5-2)

可以设: (5-3)

其中 为整数, 为16位二进制余数。将式(5-3)代入式(5-2)得:

(5-4)

因为:

(5-5)

其中 是 的高4位, 是 的低12位。将式(5-5)代入式(5-4),经整理后得:

(5-6)

再设: (5-7)

其中 为整数, 为16位二进制余数。将式(5-7)代入式(5-6),如上类推,最后得:

(5-8)

很显然,十六位二进制数 既是我们要求的CRC码。

式(5-7)是编写按字节计算CRC程序的关键,它说明计算本字节后的CRC码等于上一字节CRC码的低12位左移4位后,再加上上一字节余式CRC右移4位(也既取高4位)和本字节之和后所求得的CRC码,如果我们把4位二进制序列数的CRC全部计算出来,放在一个表里,采用查表法,每个字节算两次(半字节算一次),可以在速度和内存空间取得均衡。由此不难理解下面按半字节求CRC码的C语言程序。ptr指向发送缓冲区的首字节,len是要发送的总字节数,CRC余式表是按0x11021多项式求出的。

unsigned cal_crc(unsigned char ptr, unsigned char len) {

unsigned int crc;

unsigned char da;

unsigned int crc_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=((uchar)(crc/256))/16; / 暂存CRC的高四位 /

crc<<=4; / CRC右移4位,相当于取CRC的低12位)/

crc^=crc_ta[da^(ptr/16)]; / CRC的高4位和本字节的前半字节相加后查表计算CRC,

然后加上上一次CRC的余数 /

da=((uchar)(crc/256))/16; / 暂存CRC的高4位 /

crc<<=4; / CRC右移4位, 相当于CRC的低12位) /

crc^=crc_ta[da^(ptr&;0x0f)]; / CRC的高4位和本字节的后半字节相加后查表计算CRC,

然后再加上上一次CRC的余数 /

ptr++;

}

return(crc);

}

1、将X的最高次幂为R的生成多项式G(X)转换成对应的R+1位二进制数2、将信息码左移R位,相当于对应的信息多项式C(X)2R3、用生成多项式(二进制数)对信息码做除,得到R位的余数4、将余数拼到信息码左移后空出的位置,得到完整的CRC码例假设使用的生成多项式是G(X)=X3+X+14位的原始报文为1010,求编码后的报文1、将生成多项式G(X)=X3+X+1转换成对应的二进制除数10112、此题生成多项式有4位(R+1)(注意:4位的生成多项式计算所得的校验码为3位,R为校验码位数),要把原始报文C(X)左移3(R)位变成1010

0003、用生成多项式对应的二进制数对左移3位后的原始报文进行模2除(高位对齐),相当于按位异或:10100001011------------------00010001011------------------011得到的余位011,所以最终编码为:1010

011

CRCC——CRC程序库

/#define

CRCCCITT

0x1021#define

CCITT-REV

0x8408#define

CRC16

0x8005#define

CRC16-REV

0xA001#define

CRC32-POLYNOMIAL

0xEDB88320L/

以上为CRC除数的定义

/#define

NIL

0#define

crcupdate(d,a,t)(a)=((a)8)^(d)];#define

crcupdate16(d,a,t)(a)=((a)>>8^(t)[((a)^(d))&0x00ff])/

以上两个宏可以代替函数crcupdate和crcrevupdate

/#include

 #include

 #include

 /

函数crchware是传统的CRC算法,其返回值即CRC值

/

 unsigned

short

crchware(data,genpoly,accum)unsigned

short

data;/

输入的数据

/unsigned

short

genpoly;/

CRC除数

/unsigned

short

accum;/

CRC累加器值

/{static

int

i;data

以上就是关于计算CRC校验码问题全部的内容,包括:计算CRC校验码问题、ORACLE中实现CRC32的计算函数,SOLARIS平台、crc算法在单片机上的实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/10066065.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-04
下一篇2023-05-04

发表评论

登录后才能评论

评论列表(0条)

    保存