16位CRC算法原理及C语言实现
[技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码
[技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码1.CRC、FCS是什么CRC,全称Cyclic Redundancy Check,中⽂名称为循环冗余校验,是⼀种根据⽹络数据包或计算机⽂件等数据产⽣简短固定位数校验码的⼀种信道编码技术,主要⽤来检测或校验数据传输或者保存后可能出现的错误。
它是利⽤除法及余数的原理来作错误侦测的。
FCS,全称Frame Check Sequence,中⽂名称为帧校验序列,俗称帧尾,即计算机⽹络数据链路层的协议数据单元(帧)的尾部字段,是⼀段4个字节的循环冗余校验码。
注:CRC循环冗余校验和FCS帧校验序列是单独的概念,CRC是⼀种错误校验⽅法,FCS是帧尾校验码,FCS可以采⽤CRC校验⽅法,也可以采⽤其他校验⽅法。
2.CRC算法原理我们可以把任意的⼀串⼆进制数据表⽰为⼀个与之对应的多项式。
⽐如:⼆进制数据:1100101多项式:x^6 + x^5 + x^2+1多项式:x^6 + x^4+x^3 + x^2+1⼆进制数据:1011101有了这样的对应关系,对⼆进制数据的CRC校验就可以利⽤多项式运算规则进⾏校验计算。
CRC校验算法正是采⽤了模2除法,在数据处理⾥的具体表现为异或运算。
CRC的具体运算规则为:假设要传输的⼆进制数据为:10010110,对应的m阶多项式为:M =x^7+x^4+x^2+x^1,除数为h阶的多项式为:H=x^4+x,对应的⼆进制码为:10010,先将M乘以x^h,即将M对应的⼆进制数据后⾯加h个0,然后除以h阶的多项式H,得到的h-1阶的余数项R对应的⼆进制数据即为数据10010110的CRC校验码。
3.计算CRC校验3.1.⼿⼯计算CRC校验码M和H的多项式除法运算,可以⽤模2除法运算计算。
下⾯为以⽣成多项式为H求10010110的CRC校验码运算过程:对应到异或运算:通过⽰例即其他⾃定义的⼀些数据运算后,根据运算现象总结可以得到⼀些规律:1.每次异或运算,当从左到右⾸位为1的时候,就与⽣成多项式H异或运算,然后再左移1位;当⾸位为0的时候只将数据左移1位。
CCITT CRC-16计算原理与实现CRC-ITU
CCITT CRC-16计算原理与实现时间:2011-08-28 22:37:20 来源:作者:CRC的全称为Cy clic Redundancy Check,中文名称为循环冗余校验。
它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制。
实际上,除数据通信外,CRC在其它很多领域也是大有用武之地的。
例如我们读软盘上的文件,以及解压一个ZIP文件时,偶尔会碰到“Bad CRC”错误,由此它在数据存储方面的应用可略见一斑。
差错控制理论是在代数理论基础上建立起来的。
这里我们着眼于介绍CRC的算法与实现,对原理只能捎带说明一下。
若需要进一步了解线性码、分组码、循环码、纠错编码等方面的原理,可以阅读有关资料。
利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则,在差错控制理论中称为“生成多项式”。
1 代数学的一般性算法在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。
例如1100101 表示为1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即x6+x5+x2+1。
设编码前的原始信息多项式为P(x),P(x)的最高幂次加1等于k;生成多项式为G(x),G(x)的最高幂次等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送方编码方法:将P(x)乘以xr(即对应的二进制码序列左移r位),再除以G(x),所得余式即为R(x)。
用公式表示为T(x)=xr P(x)+R(x)接收方解码方法:将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有误。
CRC校验算法及C#程序实现
CRC校验算法及C#程序实现CRC校验可以运用于传输数据过程中的验证,发送端发送有效数据时,先根据有效数据和生成多项式(比如CCITT标准的多项式是X16+X12+X5+1)计算出CRC校验码,把CRC 校验码加到有效数据后面一起发送;当接收数据时,取出前面有效数据部分,用同样生成多项式计算出CRC校验码,然后取出接收数据后面CRC校验码部分,对比两个校验码是否相同。
如果相同,认为接收到的数据与发送的数据是一致的,传输正确;如果不同,认为传输数据出错。
CRC(循环冗余校验)算法主要是一个计算除法的过程。
算法有两个输入值,第一个是输入的信号,这通常是一个很长的数据,作为被除数。
第二个是一个与具体的CRC算法相关的多项式,称为生成多项式,用作除数。
基本的计算过程是,两者作模2除法(本质上是对应位做异或运算),余数就是CRC校验码的结果。
I、基本算法(人工笔算):以CRC16-CCITT为例进行说明,它的生成多项式是X16+X12+X5+1,CRC校验码为16位,生成多项式17位。
假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];数据流左移16位,相当于扩大256×256倍,再除以生成多项式0x11021,做不借位的除法运算(相当于按位异或),所得的余数就是CRC校验码。
发送时的数据流为6字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0]、CRC[1]、CRC[0];II、计算机算法1(比特型算法):1)将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存器;2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);3)重复第2步,直到数据流(6字节)全部移入寄存器;4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。
CRC检验原理及程序实现
CRC检验原理及程序实现引言:循环冗余检验CRC(Cyclic Redundancy Check)的检错技术应用较为广泛,由于实际的通信线路并非是理想的,它不可能将误码率(在一段时间内,传输错误的比特占所传输比特总数的比率称为误码率BER)下降到零。
因此,为了保证数据传输的可靠性,在计算机网络传输数据时,必须采用检错措施。
目前在数据链路中广泛采用循环冗余检验CRC检测技术。
1、循环冗余检验CRC的原理利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的n位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+n位,然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则,在差错控制理论中称为“生成多项式”。
代数学的一般性算法:在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。
例如1100101 表示为1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即x6+x5+x2+1。
设编码前的原始信息多项式为G(x),G(x)的最高幂次加1等于k;生成多项式为P(x),P(x)的最高幂次等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送方编码方法:将G(x)乘以xr(即对应的二进制码序列左移r位),再除以P(x),所得余式即为R(x)。
用公式表示为T(x)=xrG(x)+R(x)接收方解码方法:将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有误。
2、循环冗余码的产生及正确性检验的例子举例来说,设信息码为101001,生成多项式为1101,即P(x)=x3+x2+1,G(x)=x5+x3+1,计算CRC的过程为xrP(x) 即左移三位101001000P(x) =x3+x2+1 即R(x)=1。
MODBUS-CRC16的原理及C语言的实现
//异或多项式
}
*ptr++;
} V = ((CRC16 & 0x00FF) << 8) | ((CRC16 & 0xFF00) >> 8) ;//高低字节转换
return V;
}
最后给大家提供若干数据做参考(经过程序验证):
例如:“01”的校验码为“7E 80” “02”的校验码为“3E 81”
“01 03”的校验码为“40 21” “01 05”的校验码为“C0 23”
MODBUS 是 MODICON 公司最先倡导的一种通讯协议,经过大多数公司 的实际应用,逐 渐被认可,成为一种标准的通讯协议。 常用的 MODBUS 通讯协议有两种,一种是 MODBUS ASCII,一种是 MODBUS RTU。下面 以使用比较广泛的 MODBUS RTU 通讯协议作介绍。 Modbus RTU 通讯采用主-从方式。主设备与一个或多个从设备进行通讯。比较典型的主设备 是 PLC、PC、DCS(集散控制系统)或者 RTU(远程终端单元)。Modbus RTU 的从设备一般是 现场设备。当 Modbus RTU 主设备想要从一台从设备得到数据的时候,主设备发送一条包含 该从设备站地址、所需要的数据以及一个用于检测错误的 CRC 校验码。网络上所有其它设 备都可以接收到这条信息,但是只有地址被指定的从设备才会作出反应。 Modbus RTU 协议桢定义可概括如下:
的高、低字节进行交换。(由于发送时低字节在前) • 完成步骤 1~7 最后得到的 CRC 寄存器内容即为:CRC 校验码
◊ 计算法的 C 语言程序实现如下:
unsigned short ModBusCRC (unsigned char *ptr,unsigned char size) {
CCITT CRC-16计算原理与实现
CCITT CRC-16计算原理与实现CRC的全称为Cyclic Redundancy Check,中文名称为循环冗余校验。
它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制。
实际上,除数据通信外,CRC在其它很多领域也是大有用武之地的。
例如我们读软盘上的文件,以及解压一个ZIP文件时,偶尔会碰到“Bad CRC”错误,由此它在数据存储方面的应用可略见一斑。
差错控制理论是在代数理论基础上建立起来的。
这里我们着眼于介绍CRC的算法与实现,对原理只能捎带说明一下。
若需要进一步了解线性码、分组码、循环码、纠错编码等方面的原理,可以阅读有关资料。
利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则,在差错控制理论中称为“生成多项式”。
1 代数学的一般性算法在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。
例如 1100101 表示为1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即 x6+x5+x2+1。
设编码前的原始信息多项式为P(x),P(x)的最高幂次加1等于k;生成多项式为G(x),G(x)的最高幂次等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送方编码方法:将P(x)乘以xr(即对应的二进制码序列左移r位),再除以G(x),所得余式即为R(x)。
用公式表示为T(x)=xrP(x)+R(x)接收方解码方法:将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有误。
举例来说,设信息码为1100,生成多项式为1011,即P(x)=x3+x2,G(x)=x3+x+1,计算CRC的过程为xrP(x) x3(x3+x2) x6+x5x -------- = ---------- = -------- = (x3+x2+x) +-------- G(x) x3+x+1 x3+x+1x3+x+1即 R(x)=x。
CCITTCRC-16计算原理与实现
CCITTCRC-16计算原理与实现CCITT CRC-16计算原理与实现CRC的全称为Cyclic Redundancy Check,中⽂名称为循环冗余校验。
它是⼀类重要的线性分组码,编码和解码⽅法简单,检错和纠错能⼒强,在通信领域⼴泛地⽤于实现差错控制。
实际上,除数据通信外,CRC在其它很多领域也是⼤有⽤武之地的。
例如我们读软盘上的⽂件,以及解压⼀个ZIP⽂件时,偶尔会碰到“Bad CRC”错误,由此它在数据存储⽅⾯的应⽤可略见⼀斑。
差错控制理论是在代数理论基础上建⽴起来的。
这⾥我们着眼于介绍CRC的算法与实现,对原理只能捎带说明⼀下。
若需要进⼀步了解线性码、分组码、循环码、纠错编码等⽅⾯的原理,可以阅读有关资料。
利⽤CRC进⾏检错的过程可简单描述为:在发送端根据要传送的k位⼆进制码序列,以⼀定的规则产⽣⼀个校验⽤的r位监督码(CRC码),附在原始信息后边,构成⼀个新的⼆进制码序列数共k+r位,然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进⾏检验,以确定传送中是否出错。
这个规则,在差错控制理论中称为“⽣成多项式”。
1 代数学的⼀般性算法在代数编码理论中,将⼀个码组表⽰为⼀个多项式,码组中各码元当作多项式的系数。
例如 1100101 表⽰为1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即 x6+x5+x2+1。
设编码前的原始信息多项式为P(x),P(x)的最⾼幂次加1等于k;⽣成多项式为G(x),G(x)的最⾼幂次等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送⽅编码⽅法:将P(x)乘以xr(即对应的⼆进制码序列左移r位),再除以G(x),所得余式即为R(x)。
⽤公式表⽰为T(x)=xrP(x)+R(x)接收⽅解码⽅法:将T(x)除以G(x),如果余数为0,则说明传输中⽆错误发⽣,否则说明传输有误。
CRC16的生成及校验原理
CRC16的⽣成及校验原理计算CRC的过程,就是⽤⼀个特殊的“除法”,来得到余数,这个余数就是CRC。
它不是真正的算术上的除法!过程和算术除法过程⼀样,只是加减运算变成了XOR(异或)运算!算术上的除法:120÷9=13 余 3,120是被除数,9是除数,13是商,3是余数。
念作120除以9,或者9除120,或者9去除120!(除法的过程就不写了)这个除法计算机当然会做,但是做起来很⿇烦,因为减法有借位,很耗时间和指令!所以,计算CRC也是除法,但是⽤XOR来代替减法,这就简单多了!CRC的除法:120÷9=14 余 6,商、余数和算术除法不⼀定相同!!因为除法⽤的是XOR,⽽不是真正的减法。
以⼆进制这个计算过程:120 ⼆进制:1111000 、除数9 ⼆进制:1001 、商 14 ⼆进制:1110 余数6 ⼆进制:110从⾼位1111开始,每次进⾏⼀次XOR 的到的值后,去掉最⾼位加⼊下⼀位,每加⼀次进⾏⼀次XOR运算。
1111^1001--------------0110第⼀次XOR后得到0110,去掉最⾼位0,加⼊下⼀位0, 得1100 ,这样最⾼位是1,所以下个商是1 ,⽤^1001【很明显保留的位数与1001 保持⼀致】1100^1001--------------0101第⼆次XOR ,去掉最⾼位,加⼊下⼀位0,得1010 ,这样最⾼位是1,所以下个商是1 ,⽤^10011010^ 1001---------------0011第三次XOR,去掉最⾼位,加⼊下⼀位0,得0110 ,这样最⾼位是1,所以下个商是0 ,⽤^00000110^ 0000-------------0110最后⼀次XOR后得到0110,最⾼位的0可以消掉了,得到余数为110,即6注意,余数不是0110,⽽是110,因为最前⾯那个0已经被XOR后消掉了!可见,除法(XOR)的⽬的是逐步消掉最⾼位的1或0!由于过程是XOR的,所以商是没有意义的,我们不要。
crc16校验算法c语言
crc16校验算法c语言crc16校验算法是一种常用的数据校验方法,它可以检测出数据传输或存储过程中的错误,并提供纠错的依据。
crc16校验算法的原理是将待校验的数据看作一个多项式,用一个固定的生成多项式对其进行除法运算,得到的余数就是crc16校验码。
生成多项式的选择会影响crc16校验算法的性能,不同的应用场景可能需要不同的生成多项式。
本文主要介绍一种常用的生成多项式,即CRC-CCITT,它的二进制表示为0x1021,十六进制表示为0x11021。
本文将介绍三种实现crc16校验算法c语言的方法,分别是按位计算、按半字节计算和按单字节计算。
这三种方法的原理都是基于生成多项式对数据进行除法运算,但是具体的实现方式有所不同,各有优缺点。
下面分别介绍这三种方法,并给出相应的c语言代码。
按位计算按位计算是最直接的实现方式,它是将待校验的数据和生成多项式按位进行异或运算,得到余数。
这种方法的优点是不需要额外的存储空间,缺点是效率较低,需要循环处理每一位数据。
按位计算的c语言代码如下:#include<stdint.h>#define CRC_CCITT 0x1021//生成多项式//函数名称:crc_cal_by_bit;按位计算CRC//函数参数:uint8_t * ptr;指向发送缓冲区的首字节// uint32_t len;要发送的总字节数//函数返回值:uint16_tuint16_t crc_cal_by_bit(uint8_t*ptr, uint32_t len) {uint32_t crc =0xffff; //初始值while (len--!=0) {for (uint8_t i =0x80; i !=0; i >>=1) { //处理每一位数据crc <<=1; //左移一位if ((crc &0x10000) !=0) //如果最高位为1,则异或生成多项式crc ^=0x11021;if ((*ptr & i) !=0) //如果当前数据位为1,则异或生成多项式crc ^= CRC_CCITT;}ptr++; //指向下一个字节}uint16_t retCrc = (uint16_t)(crc &0xffff); //取低16位作为结果return retCrc;}按半字节计算按半字节计算是对按位计算的优化,它是将待校验的数据和生成多项式按半字节(4位)进行异或运算,得到余数。
CRC16C语言实现
CRC16C语⾔实现最近看到⼀个实现crc16的⼩程序,刚开始,不明觉厉,于是花了⼀个周末去know how。
CRC(Cyclic Redundancy Check)循环冗余校验是常⽤的数据校验⽅法。
先说说什么是数据校验。
数据在传输过程(⽐如通过⽹线在两台计算机间传⽂件)中,由于传输信道的原因,可能会有误码现象(⽐如说发送数字5但接收⽅收到的却是6),如何发现误码呢?⽅法是发送额外的数据让接收⽅校验是否正确,这就是数据校验。
最容易想到的校验⽅法是和校验,就是将传送的数据(按字节⽅式)加起来计算出数据的总和,并将总和传给接收⽅,接收⽅收到数据后也计算总和,并与收到的总和⽐较看是否相同。
如果传输中出现误码,那么总和⼀般不会相同,从⽽知道有误码产⽣,可以让发送⽅再发送⼀遍数据。
CRC校验也是添加额外数据做为校验码,这就是CRC校验码,那么CRC校验码是如何得到的呢? ⾮常简单,CRC校验码就是将数据除以某个固定的数(⽐如ANSI-CRC16中,这个数是0x18005),所得到的余数就是CRC校验码。
那这⾥就有⼀个问题,我们传送的是⼀串字节数据,⽽不是⼀个数据,怎么将⼀串数字变成⼀个数据呢?这也很简单,⽐如说2个字节B1,B2,那么对应的数就是(B1<<8)+B2;如果是3个字节B1,B2,B3,那么对应的数就是((B1<<16)+(B2<<8)+B3),⽐如数字是0x01,0x02,0x03,那么对应的数字就是0x10203;依次类推。
如果字节数很多,那么对应的数就⾮常⾮常⼤,不过幸好CRC只需要得到余数,⽽不需要得到商。
从上⾯介绍的原理我们可以⼤致知道CRC校验的准确率,在CRC8中出现了误码但没发现的概率是1/256,CRC16的概率是1/65536,⽽CRC32的概率则是1/2^32,那已经是⾮常⼩了,所以⼀般在数据不多的情况下⽤CRC16校验就可以了,⽽在整个⽂件的校验中⼀般⽤CRC32校验。
C语言实现CRC16校验
CRC校验C语言实现,转载请注明出处,谢谢CRC(Cyclic Redundancy Check)校验应用较为广泛,以前为了处理简单,在程序中大多数采用LRC(Longitudinal Redundancy Check)校验,LRC校验很好理解,编程实现简单。
用了一天时间研究了CRC的C语言实现,理解和掌握了基本原理和C语言编程。
结合自己的理解简单写下来。
1、CRC简介CRC检验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个检验码r位(就是CRC码),附在信息后面,构成一个新的二进制码序列数共(k+r)位,最后发送出去。
接收端根据同样的规则校验,以确定传送中是否出错。
接收端有两种处理方式:1、计算k位序列的CRC码,与接收到的CRC比较,一致则接收正确。
2、计算整个k+r位的CRC码,若为0,则接收正确。
CRC码有多种检验位数,8位、16位、32位等,原理相同。
16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(即乘以2的16次方后),除以一个多项式,最后所得到的余数就是CRC码。
求CRC码所采用的是模2运算法则,即多项式除法中采用不带借位的减法运算,运算等同于异或运算。
这一点要仔细理解,是编程的基础。
CRC-16: (美国二进制同步系统中采用) G(X) = X16 + X15 + X2 + 1CRC-CCITT: (由欧洲CCITT推荐) G(X) = X16 + X12 + X5 + 1CRC-32: G(X) = X32 + X26 + X23 + X22 + X16 +X12 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + 12、按位计算CRC采用CRC-CCITT多项式,多项式为0x11021,C语言编程时,参与计算为0x1021,这个地方得深入思考才能体会其中的奥妙,分享一下我的思路:当按位计算CRC时,例如计算二进制序列为1001 1010 1010 1111时,将二进制序列数左移16位,即为1001 1010 1010 1111 (0000 0000 0000 0000),实际上该二进制序列可拆分为1000 0000 0000 0000 (0000 0000 0000 0000) + 000 0000 0000 0000 (0000 0000 0000 0000) + 00 0000 0000 0000 (0000 0000 0000 0000) + 1 0000 0000 0000 (0000 0000 0000 0000) + ……现在开始分析运算:<1>对第一个二进制分序列求余数,竖式除法即为0x10000 ^ 0x11021运算,后面的0位保留;<2>接着对第二个二进制分序列求余数,将第一步运算的余数*2后再和第二个二进制分序列一起对0x11021求余,这一步理解应该没什么问题。
CRC原理和实现(c)
CRC原理和实现(c)一、CRC介绍RCR为Cyclical Redundancy Check,循环冗余码校验.它是利用除法及余数的原理来作错误侦测(Error Detecting)的。
CRC数值简单地说就是通过让你需要做处理的数据“除以”一个常数而得到的余数。
实际应用时,发送装置计算出CRC值并随数据一同发送给接收装置,接收装置对收到的数据重新计算CRC并与收到的CRC相比较,若两个CRC值不同,则说明数据通讯出现错误。
二、生成多项式生成多项式是,求CRC数值时所用的一个常数。
生成多项式是CRC中的除数。
一般在计算机的除法中,都使用的是减运算,但在CRC多项式除法运算中使用的是异或运算。
三、CRC检验原理(CRC16)CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1然后把CRC寄存器与8-bit的数据进行异或(异或:二进制运算相同为0,不同为1;0^0=0;0^1=1;1^0=1;1^1=0)之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的生成多项式进行异或,否则如果LSB为零,则无需进行异或。
重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据值的8次移位。
所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。
计算过程:1.设置CRC寄存器,并给其赋值FFFF(hex)。
2.将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或,并把结果存入CRC 寄存器。
3.CRC寄存器向右移一位,MSB补零,移出并检查LSB。
4.如果LSB为0,重复第三步;若LSB为1,CRC寄存器与生成多项式相异或。
5.重复第3与第4步直到8次移位全部完成。
此时一个8-bit数据处理完毕。
6. 把(本次CRC值)与(上次CRC值右移8位的值)相异或,然后取反6.重复第2至第6步直到所有数据全部处理完成。
16位CRC校验原理与算法分析
16位CRC校验原理与算法分析2007-12-14 09:37这里,不讨论CRC的纠错原理以及为什么要选下面提及的生成多项式,只是针对以下的生成多项式,如何获得CRC校验码,作一个比较详细的说明。
标准CRC生成多项式如下表:名称生成多项式简记式* 标准引用CRC-4 x4+x+1 3ITU G.704CRC-8 x8+x5+x4+1 0x31CRC-8 x8+x2+x1+1 0x07CRC-8 x8+x6+x4+x3+x2+x1 0x5ECRC-12 x12+x11+x3+x+1 80FCRC-16 x16+x15+x2+1 8005 IBM SDLCCRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCSCRC-32 x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCSCRC-32c x32+x28+x27+...+x8+x6+1 1EDC6F41 SCTP生成多项式的最高位固定的1,故在简记式中忽略最高位1了,如0x1021实际是0x11021。
I、基本算法(人工笔算):以CRC16-CCITT为例进行说明,CRC校验码为16位,生成多项式17位。
假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];数据流左移16位,相当于扩大256×256倍,再除以生成多项式0x11021,做不借位的除法运算(相当于按位异或),所得的余数就是CRC校验码。
发送时的数据流为6字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0]、CRC[1]、CRC[0];II、计算机算法1(比特型算法):1)将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存器;2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);3)重复第2步,直到数据流(6字节)全部移入寄存器;4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。
MODBUS-CRC16的原理及C语言的实现
//异或多项式
}
*ptr++;
} V = ((CRC16 & 0x00FF) << 8) | ((CRC16 & 0xFF00) >> 8) ;//高低字节转换
return V;
}
最后给大家提供若干数据做参考(经过程序验证):
例如:“01”的校验码为“7E 80” “02”的校验码为“3E21” “01 05”的校验码为“C0 23”
MODBUS 是 MODICON 公司最先倡导的一种通讯协议,经过大多数公司 的实际应用,逐 渐被认可,成为一种标准的通讯协议。 常用的 MODBUS 通讯协议有两种,一种是 MODBUS ASCII,一种是 MODBUS RTU。下面 以使用比较广泛的 MODBUS RTU 通讯协议作介绍。 Modbus RTU 通讯采用主-从方式。主设备与一个或多个从设备进行通讯。比较典型的主设备 是 PLC、PC、DCS(集散控制系统)或者 RTU(远程终端单元)。Modbus RTU 的从设备一般是 现场设备。当 Modbus RTU 主设备想要从一台从设备得到数据的时候,主设备发送一条包含 该从设备站地址、所需要的数据以及一个用于检测错误的 CRC 校验码。网络上所有其它设 备都可以接收到这条信息,但是只有地址被指定的从设备才会作出反应。 Modbus RTU 协议桢定义可概括如下:
CRC16=0xffff;
//CRC 寄存器初始值
for (a=0;a<size;a++)
//N 个字节
{
CRC16=*ptr^CRC16; for (b=0;b<8;b++)
//8 位数据
{
tmp=CRC16 & 0x0001; CRC16 =CRC16 >>1;
CRC16常见几个标准的算法及C语言实现
CRC16常见⼏个标准的算法及C语⾔实现CRC16常见的标准有以下⼏种,被⽤在各个规范中,其算法原理基本⼀致,就是在数据的输⼊和输出有所差异,下边把这些标准的差异列出,并给出C语⾔的算法实现。
CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,⾼位在后,结果与0x0000异或CRC16_CCITT_FALSE:多项式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,⾼位在前,结果与0x0000异或CRC16_XMODEM:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,⾼位在前,结果与0x0000异或CRC16_X25:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,⾼位在后,结果与0xFFFF异或CRC16_MODBUS:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,⾼位在后,结果与0x0000异或CRC16_IBM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,⾼位在后,结果与0x0000异或CRC16_MAXIM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,⾼位在后,结果与0xFFFF异或CRC16_USB:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,⾼位在后,结果与0xFFFF异或多项式产⽣:如x16+x12+x5+1x16表⽰第16位为1,x5表⽰第5位为1(1 << 16) | (1 << 12) | (1 << 5) | (1) = 0x11021但是CRC16只取低16位,写成16进制数就是 0x1021CRC16的算法原理:1.根据CRC16的标准选择初值CRCIn的值。
2.将数据的第⼀个字节与CRCIn⾼8位异或。
CRC16校验C语言程序源码-(附完整的可执行的C语言代码)
CRC16校验C语⾔程序源码-(附完整的可执⾏的C语⾔代码)CRC16校验C语⾔程序源码-(附完整的可执⾏的C语⾔代码)CRC16校验C语⾔程序源码(附完整的可执⾏的C语⾔代码)//CRC16校验在通讯中应⽤⼴泛,这⾥不对其理论进⾏讨论,只对常见的2种//实现⽅法进⾏测试。
⽅法⼀:查表法(256长度的校验表)速度快,准确,但是对于单⽚机设备存储占⽤⼤,且校验表长度⼤,输⼊时容易出现错误。
// ---------------- POPULAR POLYNOMIALS ----------------// CCITT: x^16 + x^12 + x^5 + x^0 (0x1021) // CRC-16: x^16 + x^15 + x^2 + x^0 (0x8005) #define CRC_16_POLYNOMIALS 0x8005const BYTE chCRCHTalbe[] = // CRC ⾼位字节值表{0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40};const BYTE chCRCLTalbe[] = // CRC 低位字节值表{0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1,0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB,0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8,0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74,0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40};WORD CRC16_1(BYTE* pchMsg, WORD wDataLen){BYTE chCRCHi = 0xFF; // ⾼CRC字节初始化BYTE chCRCLo = 0xFF; // 低CRC字节初始化WORD wIndex; // CRC循环中的索引while (wDataLen--){// 计算CRCwIndex = chCRCLo ^ *pchMsg++ ;chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex];chCRCHi = chCRCLTalbe[wIndex] ;}return ((chCRCHi << 8) | chCRCLo) ;}⽅法⼀:列表法(简单表)const WORD wCRCTalbeAbs[] ={0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400,};WORD CRC16_2(BYTE* pchMsg, WORD wDataLen){WORD wCRC = 0xFFFF;WORD i;BYTE chChar;for (i = 0; i < wDataLen; i++){chChar = *pchMsg++;wCRC = wCRCTalbeAbs[(chChar ^ wCRC) & 15] ^ (wCRC >> 4); wCRC = wCRCTalbeAbs[((chChar >> 4) ^ wCRC) & 15] ^ (wCRC >> 4); }return wCRC;}⽅法⼆:定义法根据CRC16/MODBUS原理直接计算,算法简单但对单⽚机计算压⼒⼤。
crc16 简式
crc16 简式CRC16是Cyclic Redundancy Check 16位校验码的简称。
它是一种常用的校验算法,广泛应用于通信、存储等领域中数据的完整性校验。
本文将介绍CRC16算法的原理、应用和计算方法。
一、CRC16算法原理CRC16算法是基于多项式除法的一种校验算法。
它将待校验的数据看作二进制数,通过与一个预设的生成多项式进行除法运算得到余数,该余数就是CRC16校验码。
生成多项式可以选择不同的值,一般情况下,常用的生成多项式为0x8005和0x1021。
二、CRC16算法应用1.通信中的数据校验在通信中,为了确保数据的传输准确性,常常需要使用CRC16校验码对数据进行校验。
发送方在发送数据之前,先计算数据的CRC16校验码,并将其添加到数据帧的尾部。
接收方在接收到数据之后,同样进行CRC16校验计算,并将计算出的校验码与接收到的校验码进行比较,以判断数据是否传输正确。
2.存储中的数据校验在存储介质中,为了防止数据损坏或篡改,常常需要使用CRC16校验码对数据进行校验。
在向存储介质写入数据时,可以计算数据的CRC16校验码,并将其添加到数据的尾部。
在读取数据时,同样进行CRC16校验计算,并比较计算出的校验码与读取到的校验码,以判断数据的完整性。
三、CRC16算法计算方法CRC16算法的计算方法比较简单,其具体步骤如下:1.预处理a)初始化一个16位的寄存器,初始值为0xFFFF。
b)将生成多项式的最高位移到寄存器的最低位。
2.数据处理a)从高位到低位依次处理每个数据(字节)。
b)计算数据与寄存器的异或值,并将其作为下一轮计算的新输入。
c)将寄存器向右移动一位。
3.结果反转a)反转寄存器的所有位。
4.结果异或a)将寄存器与0xFFFF做异或运算,得到最终的CRC16校验码。
四、总结CRC16是一种常用的校验算法,能够对数据进行快速有效的完整性校验。
它广泛应用于通信、存储等领域中,能够提高数据传输和存储的可靠性。
crc16常见的标准算法及c语言实现
crc16常见的标准算法及c语言实现CRC16是一种常用的校验算法,用于检测数据传输或存储过程中是否发生错误。
CRC16有多种标准算法,其中最常见的是CRC-16-CCITT和CRC-16-XMODEM。
以下是CRC-16-CCITT的C语言实现:```c#include <stdint.h>uint16_t crc16_ccitt(uint8_t *data, size_t length) {uint16_t crc = 0xFFFF;while (length--) {crc ^= *data++ << 8;for (size_t i = 0; i < 8; i++) {if (crc & 0x8000) {crc = (crc << 1) ^ 0x1021;} else {crc <<= 1;}}}return crc;}```以下是CRC-16-XMODEM的C语言实现:```c#include <stdint.h>uint16_t crc16_xmodem(uint8_t *data, size_t length) { uint16_t crc = 0xFFFF;while (length--) {crc ^= *data++ << 8;for (size_t i = 0; i < 8; i++) {if (crc & 0x8000) {crc = (crc << 1) ^ 0x04C11DB7;} else {crc <<= 1;}}}return crc;}```需要注意的是,以上代码中的数据是按照字节顺序进行处理的,因此在使用时需要保证数据没有字节序问题。
另外,CRC算法的实现取决于具体的标准,不同的标准可能会使用不同的初始值、多项式和反转字节顺序等参数。
因此,在实际使用时需要根据具体的标准选择合适的实现方式。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
按字节计算CRC
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, 0x1231,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,0x0a50,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,0x0af1,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=(unsigned char)(crc/256); /*以8位二进制数的形式暂存CRC的高8位*/
crc<<=8; /*左移8位,相当于CRC的低8位乘以82*/
crc^=crc_ta[da^*ptr]; /*高8位和当前字节相加后再查表求CRC,再加上以前的CRC*/
ptr++;
}
return(crc);
}
按半字节计算CRC
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=((unsigned char)(crc/256))/16; /*暂存CRC的高四位*/
crc<<=4; /*CRC右移4位,相当于取CRC的低12位)* /
crc^=crc_ta[da^(*ptr/16)]; /*CRC的高4位和本字节的前半字节相加后查表计算CRC,
然后上上一次CRC的余数*/
da=((unsigned char)(crc/256))/16; /*暂存CRC的高4位*/
crc<<=4; /*CRC右移4位,相当于CRC的低12位)*/
crc^=crc_ta[da^(*ptr&0x0f)]; /*CRC的高4位和本字节的后半字节相加后查表计算CRC,
然后再加上上一次CRC的余数*/ ptr++;
}
return(crc);
}
按位计算CRC
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*/
{
crc*=2;
crc^=0x1021;
}
else crc*=2;
if((*ptr&i)!=0)
crc^=0x1021; /*再加上本位的CRC*/
}
ptr++;
}
return(crc);
}。