第20讲 自己动手学习单片机系列讲座-CRC算法详解_第1页
第20讲 自己动手学习单片机系列讲座-CRC算法详解_第2页
第20讲 自己动手学习单片机系列讲座-CRC算法详解_第3页
第20讲 自己动手学习单片机系列讲座-CRC算法详解_第4页
第20讲 自己动手学习单片机系列讲座-CRC算法详解_第5页
已阅读5页,还剩82页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第20讲CRC算法详解青岛科技大学王泽本思想发送端根据要传送的m位二进制码序列,以一定的规则产生校验用的r位CRC码,并附在信息后边,构成一个新的二进制码序列,共(m+r)位,发送出去。接收端,将接收到的二进制序列数(m+r位)除以多项式,如果余数为0,则说明传输中无错误发生。用软件计算CRC码时,接收方可以将接收到的信息码求CRC码,与接收到的CRC码比较是否相同来判断传输数据是否有误。一CRC基本概念二进制数与多项式任意一个二进制数都对应一个多项式例:1011,0001对应的多项式为1·x7+0·x6+1·x5+1·x4+0·x3+0·x2+0·x1+1·x0即x7+x5+x4+1生成多项式任一种CRC校验都对应着一个生成多项式;生成多项式最高幂次和最低幂次的系数始终为1。名称生成多项式16进制数应用举例CRC4x4+x+1ITUG.704CRC8/MAXIMx8+x5+x4+10x31MAXIM芯片CRC16x16+x15+x2+10x8005MODBUSCRC16-ITU*x16+x12+x5+10x1021ISOHDLCCRC32x32+x26+···+x2+x+10x04C11DB7ZIP,RAR,IEEE1394CRC32Cx32+x28+···+x8+x6+10x1EDC6F41SCTP*CRC16-ITU以前称作CRC16-CITT二CRC算法基本原理CRC的本质是模-2除法的余数。求CRC码所采用模2加减运算法则,即是不带进位和借位的按位加减,这种加减运算实际上是逻辑上的异或运算,加法和减法等价;乘法和除法运算与普通代数式的乘除法运算是一样。假定要发送的二进制数对应的多项式为K(x),生成多项式为G(x),最高幂次为r。设xr·K(x)/G(x)得到的余数多项式为R(x)。则R(x)对应的二进制数即为CRC校验码,位数为r位。用数学表达式表示为xr·K(x)=G(x)·Q(x)+R(x)其中Q(x)为得到的整数商多项式。举例:采用CRC4校验,传送的信息码为0101,1001,生成多项式为x4+x+1。解:信息码0101,1001对应多项式为x6+x4+x3+1,乘以x4得x10+x8+x7+x4,对应二进制10110010000生成多项式x4+x+1对应被除数10011。10011

10110010000

10011

101010000

10011

1100000

10011

101100

100111010101011异或运算异或运算余数余数余数CRC码异或运算异或运算为0不做处理为0不做处理算法特点m位信息码添加r位0构成要处理的码块每次处理5位,可设置一个5位寄存器,初始值为0。信息码左移一位进入REG0检测寄存器中的最高位REG4为1,将寄存器与10011异或运算,为0返回步骤3若没处理完m+r位,返回步骤3;否则取REG3…0作为CRC码REG4REG3REG2REG1REG010110010000左移左移缺点:算法用到5位寄存器,不方便简单改进m位信息码添加r位0构成要处理的码块每次处理4位,可设置一个4位寄存器,初始值为0。信息码左移一位进入REG0,同时检测寄存器中的移出位为1,将寄存器与0011异或运算,为0返回步骤3若没处理完m+r位,返回步骤3;否则寄存器内容为CRC码REG3REG2REG1REG010110010000左移左移生成多项式最高位始终为1,可省掉该位左移待检测的标志位crcReg实际只用4位16位crcReg=0x0000;实际编程时的考虑

crcReg寄存器为16位,Bit0-7位存储加载的信息码字节crcReg寄存器的Bit7-11用于crc码,Bit12用于检测左移出的值为1或0。加载要处理的8位信息码Bit0Bit7Bit8Bit11Bit9Bit10Bit12/********************simpcrc40.c**************************************/#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;uint8simpCrc4(uint8*p,intn){uint16crcReg=0x0000;//初始值

inti,j;for(i=0;i<n;i++)//信息码共n个字节

{crcReg^=p[i];for(j=0;j<8;j++) //处理一个字节

{crcReg<<=1; //左移一位

if(crcReg&0x1000) //移出的值为1,异或多项式

crcReg^=0x0300;}}注:以上算法得到的CRC值和实际CRC4算法不相同。因CRC4实际模型与上述有细微差别,暂时把这个问题先放一下。for(i=0;i<4;i++) //补4个0,以便处理完最后一个字节的低四位

{crcReg<<=1;if(crcReg&0x1000)crcReg^=0x0300;}crcReg>>=8; //右移8位

return(crcReg&0x0F);//返回低4位值}intmain(){ uint8crcReg; uint8p[]={0x16,0x32,0xA9}; crcReg=simpCrc4(p,3); printf("0x%x",crcReg); return(0);}运行结果左移待检测的标志位crcReg实际只用16位32位crcReg=0x00000000;

crcReg寄存器为32位,低8位存储加载的信息码字节crcReg寄存器的Bit8-23用于CRC码,Bit24位用于检测左移出的值为1或0。以上算法可扩充到其它宽度的CRC码,以16位CRC码为例加载要处理的8位信息码Bit0Bit7Bit8Bit23Bit24···/********************simpcrc160.c******************************/#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;typedefunsignedintuint32;uint16simpCrc16(uint8*p,intn){uint32crcReg=0x00000000;//初始值

inti,j;for(i=0;i<n;i++)//信息码共n个字节

{crcReg^=p[i];for(j=0;j<8;j++) //处理一个字节

{crcReg<<=1; //左移一位

if(crcReg&0x1000000) //移出的值为1,异或多项式

crcReg^=0x102100;}}for(i=0;i<16;i++) //补4个0,以便处理完最后一个字节的低四位

{crcReg<<=1;if(crcReg&0x1000000)crcReg^=0x102100;}crcReg>>=8; //右移8位

return(crcReg&0xFFFF);//返回低4位值}intmain(){ uint16crcReg; uint8p[]={0x16,0x32,0xA9}; crcReg=simpCrc16(p,3); printf("0x%x",crcReg); return(0);}运行结果注:实际上此程序计算的是CRC16/XMODEM三CRC寄存器的优化处理第二节介绍的算法优缺点分析优点算法简单直观,同原理直接对应,易于理解缺点算法开始时,计算了多位无用的初值。算法结束前,补零运算仅仅是为了将最后一个字节每一位都处理完。CRC寄存器用后8位存放新读入的信息码字节;另外用单独1位存放移出的位。算法不优美,显得业余。正常算法(当前字节紧跟下一字节)101011011001第i字节后四位第i+1字节(1)移出一位1异或0110

10110101

10110011110

1

0110(2)移出一位0CRC寄存器的优化处理10101100001110011100(3)移出一位1异或0101

1001(4)移出一位1,异或001101101001最后结果优化算法当前字节后面补零,处理完一个字节前4位后,得到的结果10100000第i字节后四位(1)移出一位1异或0111

00000100

00000011已处理前四位,后面已补了4个0(2)移出一位01110

0000(3)移出一位1,异或11

00

0000001111

11

0000(4)移出一位1,异或1

0

00

000000111

0

11

000011011001下一字节XOR移完后四位得到的结果01101001最后结果从以上分析看出两种算法结果一样。第二种算法每次处理一个字节,得到的结果与下一字节异或去掉前导的无用初值不需要末位补零CRC4寄存器优化算法CrcReg00000000前四位有效待处理的信息段每次进入一个字节与crcReg作异或运算,然后移位比较移出的位是否为1,若为1,则异或多项式0x30。直到8次移位处理完一字节。继续处理下一字节,直到信息码所有字节处理完毕将crcReg0右移4位得到CRC码。/******************simpcrc41.c*********************************/#include<stdio.h>typedefunsignedcharuint8;uint8simpCrc4(uint8*p,intn){uint8crcReg=0x00;//初始值

inti,j;for(i=0;i<n;i++)//信息码共n个字节

{crcReg^=p[i];for(j=0;j<8;j++) //处理一个字节

{if(crcReg&0x80) //移出的值为1,异或多项式

{ crcReg<<=1; crcReg^=0x30;}else crcReg<<=1; }}crcReg>>=4; //右移4位

return(crcReg&0x0F);//返回低4位值}intmain(){ uint8crcReg; uint8p[]={0x16,0x32,0xA9}; crcReg=simpCrc4(p,3); printf("0x%x",crcReg); return(0);}运行结果注:以上算法得到的CRC值和实际CRC4算法不相同。因CRC4实际模型与上述有细微差别,暂时把这个问题先放一下。CRC16寄存器优化算法CrcRegBit7Bit0Bit8Bit15······Bit7Bit0···信息码字节XOR待处理的信息段每次进入一个字节左移8位与crcReg作异或运算,然后左移1位,若移出位为1,则异或多项式0x1021。直到8次移位处理完一字节。继续处理下一字节,直到信息码所有字节处理完毕/****************************simpcrc161.c*******************************/#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;uint16simpCrc16(uint8*p,intn){uint16crcReg=0x0000;//初始值

inti,j;for(i=0;i<n;i++)//信息码共n个字节

{crcReg^=p[i]<<8;for(j=0;j<8;j++) //处理一个字节

{if(crcReg&0x8000) //移出的值为1,异或多项式

{ crcReg<<=1; crcReg^=0x1021;} else crcReg<<=1; }}return(crcReg);//返回}intmain(){ uint16crcReg; uint8p[]={0x16,0x32,0xA9}; crcReg=simpCrc16(p,3); printf("0x%x",crcReg); return(0);}运行结果注:实际上此程序计算的是CRC16/XMODEM四CRC的参数模型CRC参数模型是编写CRC程序时必须要参考的模型,对CRC16来说,虽然都是16位CRC校验,但参数不同,最后CRC码也不同,下面是CRC16/XMODEM模型,前几节的CRC16程序可直接应用于该模型 Name:“CRC16/XMODEM" Width:16 Poly:0x1021 Init:0x0000 RefIn:False RefOut:False XorOut:0x0000 Alias:CRC16/ZMODEM,CRC16/ACORN Use:

Poly:生成多项式的16进制数(省略最高位的1),例如 CRC-4/ITU的生成项为x16+x12+x5+1,对应十六 进,0001,0000,0010,0001,省略最高位的二进制 是001,0000,0010,0001,对应16进制0x1021

Init: CRC寄存器初始化值。CRC参数模型解释 Name:CRC名称 Width:CRC比特数 RefIn 取值TRUE或FALSE。

FALSE,表示信息码不用“颠倒”;TRUE,表示信 息码每个字节都要先“颠倒”。

注:若采用直接算法编程,应颠倒后再补r位0 RefOut 取值TRUE或FALSE。 FALSE,表示计算结束后,寄存器中的值直接进 入XOROUT处理即可。TRUE,表示计算结束 后,寄存器中的值要先“颠倒”,再进入XOROUT处 理。注意,这是将整个寄存器的值颠倒,如果只 是对各个字节各自颠倒,那结果值就错误了。 XorOut 这个值与经RefOut后的寄存器的值相XOR,得 到的值就是最终正式的CRC值! Check(可选) 这不是定义值的一部分。是字串“123456789”用该 CRC参数模型计算得到的CRC值,作为参考。

Use(可选) 这不是模型定义值的一部分。仅仅表示该算法应 用在什么地方 对RefIn=False,RefOut=False情况,第三节的程序很容易规格化为CRC参数模型的方式。 先给出这种模型的规格化算法,常用的有以下两种CRC8/ITU算法Name:CRC8/ITUWidth:8Poly:0x07Init:0x00RefIn:FalseRefOut:FalseXorOut:0x55CRC16/XMODEM算法Name:CRC16/XMODEMWidth:16Poly:0x1021Init:0x0000RefIn:FalseRefOut:FalseXorOut:0x0000直接CRC左移算法1(字节不逆序左移,多项式不逆序)设定crcReg寄存器初始值;取信息码一字节(视情况需或不需移位)异或crcReg寄存器;左移1位,若移出位为1,则多项式异或crcReg;若没处理完一个字节,返回第3步;若还有未处理完的信息字节,返回第2步;得到的crcReg异或XorOut值,得到CRC码。条件RefIN=False;RefOut=False/*********************simpcrcleft.c*********************************/#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;uint8simpCrc8(uint8*p,intn,uint8poly,uint8initReg,uint8xorOut){uint8crcReg=initReg;//初始值

inti,j;for(i=0;i<n;i++)//信息码共n个字节

{crcReg^=p[i]; //不需左移

for(j=0;j<8;j++) //处理一个字节

{if(crcReg&0x80)//移出的值为1,异或多项式

{ crcReg<<=1; crcReg^=poly;} else crcReg<<=1; }}return(crcReg^xorOut);}uint16simpCrc16(uint8*p,intn,uint16poly,uint16initReg,uint16xorOut){uint16crcReg=initReg;//初始值

inti,j;for(i=0;i<n;i++)//信息码共n个字节

{crcReg^=p[i]<<8; //需要左移8位for(j=0;j<8;j++) //处理一个字节

{if(crcReg&0x8000)//移出的值为1,异或多项式

{ crcReg<<=1; crcReg^=poly;} else crcReg<<=1; }}return(crcReg^xorOut);//返回}intmain(){ uint8crcReg8; uint16crcReg16; uint8p[]={0x16,0x32,0xA9}; crcReg8=simpCrc8(p,3,0x07,0x00,0x00); printf("CRC8\t0x%x\n",crcReg8); crcReg16=simpCrc16(p,3,0x1021,0x0000,0x0000); printf("CRC16\t0x%x",crcReg16); return(0);}五信息码字节逆序CRC算法字节逆序算法描述字节y=0x00;x每次左移一位,检测最高位,若为1,则加上数组中对应的值。最后得到的y即为x的逆序。0x010x020x040x080x100x200x400x80待逆序的字节xbitVal[8]=例:11000010的逆序为01000011字节逆序若RefIn=TrueRefOut=True,此时需多项式逆序左移,最后结果逆序,才能得CRC码两种逆序算法模型CRC4/ITU算法Name:CRC4/ITUWidth:4Poly:0x03Init:0x00RefIn:TrueRefOut:TrueXorOut:0x00MODBUS通讯协议中的CRC算法Name:CRC16/ModbusWidth:16Poly:0x8005Init:0xFFFFRefIn:TrueRefOut:TrueXorOut:0x0000CRC4/ITU算法(字节逆序)CrcReg00000000前四位有效crcReg0设为8位无符号数(实际只有高四位有效);待处理的信息段每次进入一个字节逆序后与crcReg作异或运算,然后左移1位,若移出位为1,则异或多项式0x30。直到8次左移当前字节都处理完毕。处理下一个字节,直到信息码的最后一个字节将crcReg逆序得到CRC码。/***********************crc4invert.c**********************/#include<stdio.h>typedefunsignedcharuint8;uint8invertByte(uint8x) //字节逆序{uint8bitVal[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};uint8y=0x00;inti;for(i=0;i<=7;i++){if(x&0x80)y+=bitVal[i];x<<=1;}return(y);}uint8simpCrc4(uint8*p,intn){uint8crcReg=0x00;

inti,j;for(i=0;i<n;i++){crcReg^=invertByte(p[i]);for(j=0;j<8;j++){if(crcReg&0x80){ crcReg<<=1; crcReg^=0x30;}elsecrcReg<<=1;}}crcReg=invertByte(crcReg);return(crcReg);}intmain(void){uint8x[3]={0x16,0x32,0xA9};uint8crcCode8;crcCode8=simpCrc4(x,3);printf("0x%x\n",crcCode8);return(0);}运行结果注:以上算法得到的CRC值和实际CRC4算法相同。比较前面CRC4算法可知,仅仅添加字节逆序和crcReg逆序CRC16/Modbus字节逆序算法CrcRegBit7Bit0Bit8Bit15······Bit7Bit0···逆序的信息码字节XOR待处理的信息段每次进入一个字节逆序后左移8位与crcReg作异或运算。然后左移1位,若移出位为1,则异或多项式0x30。直到8次左移当前字节都处理完毕。处理下一个字节,直到信息码的最后一个字节将crcReg逆序得到CRC码。/*********************crc16invert.c**************************/#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;uint8invertByte(uint8x){uint8bitVal[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};uint8y=0x00;inti;for(i=0;i<=7;i++){if(x&0x80)y+=bitVal[i];x<<=1;}return(y);}uint16invertWord(uint16x){uint16bitVal[16]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};uint16y=0x0000;inti;for(i=0;i<=15;i++){if(x&0x8000)y+=bitVal[i];x<<=1;}return(y);}uint16simpCrc16(unsignedchar*p,intn){uint16crcReg=0xFFFF;inti,j;for(i=0;i<n;i++){crcReg^=invertByte(p[i])<<8;for(j=0;j<8;j++){ if(crcReg&0x8000) { crcReg<<=1; crcReg^=0x8005; } else crcReg<<=1;}}return(invertWord(crcReg));}intmain(void){uint8x[3]={0x16,0x32,0xA9};uint16crcCode16;crcCode16=simpCrc16(x,3);printf("0x%x\n",crcCode16);return(0);}运行结果缺点分析信息码逆序算法每个字节逆序,算法开销大。计算得到最后结果需要再次逆序得到CRC码。考察字节不逆序,多项式逆序。字节左移改为右移,若移出为为1,异或逆序多项式。六信息码逆序算法优化不需要信息字节的逆序和最后结果的逆序;仅仅了逆序多项式;由于多项式是固定的,逆序一次即可。减小了逆序所需要的开销。设信息码的一字节为 10010101字节逆序左移算法10101001

001101100010011101110011010000111100

10010101110010001101100111011100001011000011多项式逆序字节右移算法镜像逆序得CRC码直接CRC算法2(多项式逆序,字节不逆序右移)设定crcReg寄存器初始值;取信息码一字节异或crcReg寄存器;右移1位,若移出位为1,则逆序多项式异或crcReg;若没处理完一个字节,返回第3步;若还有未处理完的信息字节,返回第2步;得到的crcReg异或XorOut值,得到CRC码。条件RefIN=True;RefOut=True/**********************crc4right.c*******************************************/#include<stdio.h>typedefunsignedcharuint8;uint8simpCrc4R(uint8*p,intn,uint8poly,uint8initReg,uint8xorOut){inti,j;uint8crcReg=initReg;for(i=0;i<n;i++){crcReg^=p[i];for(j=0;j<8;j++){if(crcReg&0x0001){ crcReg>>=1; crcReg^=poly;//}else crcReg>>=1;}}return(crcReg^xorOut);}intmain(void){uint8x[3]={0x16,0x32,0xA9};uint8crcCode8;crcCode8=simpCrc4R(x,3,0x0C,0x00,0x00);//多项式逆序0x0cprintf("HEX%x\n",crcCode8);return(0);}运行结果CRC16/Modbus通讯协议所用的算法描述Name:CRC16/ModbusWidth:16Poly:0x8005Init:0xFFFFRefIn:TrueRefOut:TrueXorOut:0x0000从描述看和CRC4ITU算法基本一样,除了初始值为0xFFFF之外,因此算法在CRC4基础上稍加修改即可。#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;uint16simpCrc16R(uint8*p,intn,uint16poly,uint16initReg,uint16xorOut){inti,j;uint16crcReg=initReg;for(i=0;i<n;i++){crcReg^=p[i];for(j=0;j<8;j++){if(crcReg&0x0001){ crcReg>>=1; crcReg^=poly;}else crcReg>>=1;}}return(crcReg^xorOut);}intmain(void){uint8x[3]={0x16,0x32,0xA9};uint16crcCode16;

//多项式逆序0xA001crcCode16=simpCrc16R(x,3,0xA001,0xFFFF,0x0000);printf("0x%x\n",crcCode16);return(0);}运行结果查询表CRC算法原理直接CRC算法1和2的开销分析无论CRC4,CRC8,CRC16还是CRC32,都需要两重循环。第一重循环从信息码中加载一字节数据。第二重循环进行8次移位处理这一字节数据。有大量的开销消耗在每字节8次移位异或运算中。减少算法开销的总体思路每字节8位数据,共256种组合;对应256种CRC码。对字节数据从0-255,预先计算出对应的CRC码,存储为一张CRC查询表。对信息码每字节数据用查表方法去计算CRC值。前几节讲的CRC直接算法1和2,都是计算多字节信息码的,稍加修改就可计算单字节数据的CRC码。以生成CRC查询表crcReg寄存器初始值始设为0;crcReg寄存器异或要计算的字节对要计算的8bit数据右移1位,若移出位为1,则异或poly。若未处理完8位数据,返回第3步继续返回CRC结果,不要异或xorOut;生成“右移CRC查询表”算法/****************************rightcrc4table.c**********************************/#include<stdio.h>typedefunsignedcharuint8;uint8crcTable[256];uint8crc4Byte(uint8mCode){uint8crcReg=0x00;inti;crcReg^=mCode;for(i=0;i<8;i++){if(crcReg&0x01){ crcReg>>=1; crcReg^=0x0C;}CRC4/ITU右移查询表else crcReg>>=1;}return(crcReg);}voidcrc4Table(void){

uint8mCode=0x00; intk; for(k=0x00;k<=0xFF;k++) { crcTable[k]=crc4Byte(mCode); mCode++; }}intmain(void){ inti; FILE*fp=fopen("crc4table.txt","w"); crc4Table(); for(i=0;i<=255;i++) { if(0==i%16&&0!=i) { fprintf(fp,"\n\r",crcTable[i]); } fprintf(fp,"0x%x",crcTable[i]); if(255!=i) fprintf(fp,","); } fclose(fp); return(0);}CRC4查询表0x0,0x7,0xe,0x9,0x5,0x2,0xb,0xc,0xa,0xd,0x4,0x3,0xf,0x8,0x1,0x6,0xd,0xa,0x3,0x4,0x8,0xf,0x6,0x1,0x7,0x0,0x9,0xe,0x2,0x5,0xc,0xb,0x3,0x4,0xd,0xa,0x6,0x1,0x8,0xf,0x9,0xe,0x7,0x0,0xc,0xb,0x2,0x5,0xe,0x9,0x0,0x7,0xb,0xc,0x5,0x2,0x4,0x3,0xa,0xd,0x1,0x6,0xf,0x8,0x6,0x1,0x8,0xf,0x3,0x4,0xd,0xa,0xc,0xb,0x2,0x5,0x9,0xe,0x7,0x0,0xb,0xc,0x5,0x2,0xe,0x9,0x0,0x7,0x1,0x6,0xf,0x8,0x4,0x3,0xa,0xd,0x5,0x2,0xb,0xc,0x0,0x7,0xe,0x9,0xf,0x8,0x1,0x6,0xa,0xd,0x4,0x3,0x8,0xf,0x6,0x1,0xd,0xa,0x3,0x4,0x2,0x5,0xc,0xb,0x7,0x0,0x9,0xe,0xc,0xb,0x2,0x5,0x9,0xe,0x7,0x0,0x6,0x1,0x8,0xf,0x3,0x4,0xd,0xa,0x1,0x6,0xf,0x8,0x4,0x3,0xa,0xd,0xb,0xc,0x5,0x2,0xe,0x9,0x0,0x7,0xf,0x8,0x1,0x6,0xa,0xd,0x4,0x3,0x5,0x2,0xb,0xc,0x0,0x7,0xe,0x9,0x2,0x5,0xc,0xb,0x7,0x0,0x9,0xe,0x8,0xf,0x6,0x1,0xd,0xa,0x3,0x4,0xa,0xd,0x4,0x3,0xf,0x8,0x1,0x6,0x0,0x7,0xe,0x9,0x5,0x2,0xb,0xc,0x7,0x0,0x9,0xe,0x2,0x5,0xc,0xb,0xd,0xa,0x3,0x4,0x8,0xf,0x6,0x1,0x9,0xe,0x7,0x0,0xc,0xb,0x2,0x5,0x3,0x4,0xd,0xa,0x6,0x1,0x8,0xf,0x4,0x3,0xa,0xd,0x1,0x6,0xf,0x8,0xe,0x9,0x0,0x7,0xb,0xc,0x5,0x2/*******************************rightcrc16table.c*********************/#include<stdio.h>typedefunsignedcharuint8;typedefunsignedshortintuint16;uint16crcTable[256];uint16crc16Byte(uint8mCode,uint16poly){uint16crcReg=0x0000;inti;crcReg^=mCode;for(i=0;i<8;i++){if(crcReg&0x0001){ crcReg>>=1; crcReg^=poly;}CRC16/MODBUS右移查询表 else crcReg>>=1;}return(crcReg);}voidcrc16Table(void){ uint8mCode=0x00; intk; for(k=0x00;k<=0xFF;k++) { crcTable[k]=crc16Byte(mCode,0xA001); mCode++; }}intmain(void){ inti; uint8p[]={0x16,0x32,0xA9}; FILE*fp=fopen("crc16table.txt","w"); crc16Table(); for(i=0;i<=255;i++) { if(0==i%8&&0!=i) { fprintf(fp,"\n\r",crcTable[i]); } fprintf(fp,"0x%x\t",crcTable[i]); if(255!=i) fprintf(fp,","); } fclose(fp); return(0);}0x0 ,0xc0c1 ,0xc181 ,0x140 ,0xc301 ,0x3c0 ,0x280 ,0xc241 ,0xc601 ,0x6c0 ,0x780 ,0xc741 ,0x500 ,0xc5c1 ,0xc481 ,0x440 ,0xcc01 ,0xcc0 ,0xd80 ,0xcd41 ,0xf00 ,0xcfc1 ,0xce81 ,0xe40 ,0xa00 ,0xcac1 ,0xcb81 ,0xb40 ,0xc901 ,0x9c0 ,0x880 ,0xc841 ,0xd801 ,0x18c0 ,0x1980 ,0xd941 ,0x1b00 ,0xdbc1 ,0xda81 ,0x1a40 ,0x1e00 ,0xdec1 ,0xdf81 ,0x1f40 ,0xdd01 ,0x1dc0 ,0x1c80 ,0xdc41 ,0x1400 ,0xd4c1 ,0xd581 ,0x1540 ,0xd701 ,0x17c0 ,0x1680 ,0xd641 ,0xd201 ,0x12c0 ,0x1380 ,0xd341 ,0x1100 ,0xd1c1 ,0xd081 ,0x1040 ,0xf001 ,0x30c0 ,0x3180 ,0xf141 ,0x3300 ,0xf3c1 ,0xf281 ,0x3240 ,0x3600 ,0xf6c1 ,0xf781 ,0x3740 ,0xf501 ,0x35c0 ,0x3480 ,0xf441 ,0x3c00 ,0xfcc1 ,0xfd81 ,0x3d40 ,0xff01 ,0x3fc0 ,0x3e80 ,0xfe41 ,0xfa01 ,0x3ac0 ,0x3b80 ,0xfb41 ,0x3900 ,0xf9c1 ,0xf881 ,0x3840 ,0x2800 ,0xe8c1 ,0xe981 ,0x2940 ,0xeb01 ,0x2bc0 ,0x2a80 ,0xea41 ,0xee01 ,0x2ec0 ,0x2f80 ,0xef41 ,0x2d00 ,0xedc1 ,0xec81 ,0x2c40 ,0xe401 ,0x24c0 ,0x2580 ,0xe541 ,0x2700 ,0xe7c1 ,0xe681 ,0x2640 ,CRC16/modbus查询表0x2200 ,0xe2c1 ,0xe381 ,0x2340 ,0xe101 ,0x21c0 ,0x2080 ,0xe041 ,0xa001 ,0x60c0 ,0x6180 ,0xa141 ,0x6300 ,0xa3c1 ,0xa281 ,0x6240 ,0x6600 ,0xa6c1 ,0xa781 ,0x6740 ,0xa501 ,0x65c0 ,0x6480 ,0xa441 ,0x6c00 ,0xacc1 ,0xad81 ,0x6d40 ,0xaf01 ,0x6fc0 ,0x6e80 ,0xae41 ,0xaa01 ,0x6ac0 ,0x6b80 ,0xab41 ,0x6900 ,0xa9c1 ,0xa881 ,0x6840 ,0x7800 ,0xb8c1 ,0xb981 ,0x7940 ,0xbb01 ,0x7bc0 ,0x7a80 ,0xba41 ,0xbe01 ,0x7ec0 ,0x7f80 ,0xbf41 ,0x7d00 ,0xbdc1 ,0xbc81 ,0x7c40 ,0xb401 ,0x74c0 ,0x7580 ,0xb541 ,0x7700 ,0xb7c1 ,0xb681 ,0x7640 ,0x7200 ,0xb2c1 ,0xb381 ,0x7340 ,0xb101 ,0x71c0 ,0x7080 ,0xb041 ,0x5000 ,0x90c1 ,0x9181 ,0x5140 ,0x9301 ,0x53c0 ,0x5280 ,0x9241 ,0x9601 ,0x56c0 ,0x5780 ,0x9741 ,0x5500 ,0x95c1 ,0x9481 ,0x5440 ,0x9c01 ,0x5cc0 ,0x5d80 ,0x9d41 ,0x5f00 ,0x9fc1 ,0x9e81 ,0x5e40 ,0x5a00 ,0x9ac1 ,0x9b8

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论