您当前的位置:五五电子网电子知识plc技术PLC入门CRC校验原理和其C语言实现分析 正文
CRC校验原理和其C语言实现分析

CRC校验原理和其C语言实现分析

点击数:7343 次   录入时间:03-04 11:59:53   整理:http://www.55dianzi.com   PLC入门

CRC校验码的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+ r)位,最后发送出去。在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
      在数据存储和数据通讯领域,CRC无处不在:著名的通讯协议X.25的FCS(帧检错序列)采用的是CRC. CCITT,ARJ、LHA等压缩工具软件采用的是CRC32,磁盘驱动器的读写采用了CRC16,通用的图像存储格式GIF、TIFF等也都用CRC作为检错手段。
      CRC的本质是模-2除法的余数,采用的除数不同,CRC的类型也就不一样。通常,CRC的除数用生成多项式来表示。最常用的CRC码的生成多项式有CRC16,CRC32.
      以CRC16为例,16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(既乘以2^16)后,再除以一个多项式,最后所得到的余数既是 CRC码,如下式所示,其中K(X)表示n位的二进制序列数,G(X)为多项式,Q(X)为整数,R(X)是余数(既CRC码)。
K(X)>>16=G(x)Q(x)+R(x)
      求CRC码所采用模2加减运算法则,既是不带进位和借位的按位加减,这种加减运算实际上就是逻辑上的异或运算,加法和减法等价,乘法和除法运算与普通代数式的乘除法运算是一样,符合同样的规律。生成CRC码的多项式如下,其中CRC-16和CRC-CCITT产生16位的CRC码,而CRC-32则产生的是32位的CRC码 PLC资料网
      接收方将接收到的二进制序列数(包括信息码和CRC码)除以多项式,如果余数为0,则说明传输中无错误发生,否则说明传输有误,关于其原理这里不再多述。用软件计算CRC码时,接收方可以将接收到的信息码求CRC码,比较结果和接收到的CRC码是否相同。
      CCITT推荐的高级数据链路控制规程HDLC的帧校验序列FCS中,使用CCITT-16即CRC16,其生成多项式为G(x)=x16+x12+x5 +1, CRC-32的生成多项式为G(x)=x32+x26+x23+x22+x16+x11+x10+x16+x8+x7+x5+x4+x2+x+1

      以上是摘录的一段介绍,是不是觉得很玄?我第一次看也是觉得很晕,后来查询了一些规约和协议的实现资料以后,才恍然大悟。以下是我实现的一段C++代码,只实现了CRC16,CRC32的实现基本类似,网上有很多资源。其实实现起来非常简单,就是查表、异或运算而已!查表法实现起来比较简单,耗资源也比较少,速度较快。只要通信双方采用的同样的余数表,就可以正确进行CRC校验。余数表并没有硬性规定。许多程序还把余数表做成自动生成,那样适用性就更好了。

//CRC计算主函数:
//内容:
#include "CrcCode.h"
PLC
using namespace std;

unsigned short int CrcCode::CrcCode16(const char *CrcSrcCode,const size_t CodeLength)
{
      unsigned short CRC_Code[]={
              0x0673,0x1652,0x2631,0x3610,0x46F7,0x56D6,0x66B5,0x7694,0x877B,0x975A,//10
              0xA739,0xB718,0xC7FF,0xD7DE,0xE7BD,0xF79C,0x1442,0x0463,0x3400,0x2421,//20
              0x54C6,0x44E7,0x7484,0x64A5,0x954A,0x856B,0xB508,0xA529,0xD5CE,0xC5EF,//30
              0xF58C,0xE5AD,0x2211,0x3230,0x0253,0x1272,0x6295,0x72B4,0x42D7,0x52F6,//40
              0xA319,0xB338,0x835B,0x937A,0xE39D,0xF3BC,0xC3DF,0xD3FE,0x3020,0x2001,//50
              0x1062,0x0043,0x70A4,0x6085,0x50E6,0x40C7,0xB128,0xA109,0x916A,0x814B,//60 PLC资料网
              0xF1AC,0xE18D,0xD1EE,0xC1CF,0x4EB7,0x5E96,0x6EF5,0x7ED4,0x0E33,0x1E12,//70
              0x2E71,0x3E50,0xCFBF,0xDF9E,0xEFFD,0xFFDC,0x8F3B,0x9F1A,0xAF79,0xBF58,//80
              0x5C86,0x4CA7,0x7CC4,0x6CE5,0x1C02,0x0C23,0x3C40,0x2C61,0xDD8E,0xCDAF,//90
              0xFDCC,0xEDED,0x9D0A,0x8D2B,0xBD48,0xAD69,0x6AD5,0x7AF4,0x4A97,0x5AB6,//100
              0x2A51,0x3A70,0x0A13,0x1A32,0xEBDD,0xFBFC,0xCB9F,0xDBBE,0xAB59,0xBB78,//110
              0x8B1B,0x9B3A,0x78E4,0x68C5,0x58A6,0x4887,0x3860,0x2841,0x1822,0x0803,//120
              0xF9EC,0xE9CD,0xD9AE,0xC98F,0xB968,0xA949,0x992A,0x890B,0x97FB,0x87DA,//130 PLC
              0xB7B9,0xA798,0xD77F,0xC75E,0xF73D,0xE71C,0x16F3,0x06D2,0x36B1,0x2690,//140
              0x5677,0x4656,0x7635,0x6614,0x85CA,0x95EB,0xA588,0xB5A9,0xC54E,0xD56F,//150
              0xE50C,0xF52D,0x04C2,0x14E3,0x2480,0x34A1,0x4446,0x5467,0x6404,0x7425,//160
              0xB399,0xA3B8,0x93DB,0x83FA,0xF31D,0xE33C,0xD35F,0xC37E,0x3291,0x22B0,//170
              0x12D3,0x02F2,0x7215,0x6234,0x5257,0x4276,0xA1A8,0xB189,0x81EA,0x91CB,//180
              0xE12C,0xF10D,0xC16E,0xD14F,0x20A0,0x3081,0x00E2,0x10C3,0x6024,0x7005,//190
              0x4066,0x5047,0xDF3F,0xCF1E,0xFF7D,0xEF5C,0x9FBB,0x8F9A,0xBFF9,0xAFD8,//200 PLC资料网
              0x5E37,0x4E16,0x7E75,0x6E54,0x1EB3,0x0E92,0x3EF1,0x2ED0,0xCD0E,0xDD2F,//210
              0xED4C,0xFD6D,0x8D8A,0x9DAB,0xADC8,0xBDE9,0x4C06,0x5C27,0x6C44,0x7C65,//220
              0x0C82,0x1CA3,0x2CC0,0x3CE1,0xFB5D,0xEB7C,0xDB1F,0xCB3E,0xBBD9,0xABF8,//230
              0x9B9B,0x8BBA,0x7A55,0x6A74,0x5A17,0x4A36,0x3AD1,0x2AF0,0x1A93,0x0AB2,//240
              0xE96C,0xF94D,0xC92E,0xD90F,0xA9E8,0xB9C9,0x89AA,0x998B,0x6864,0x7845,//250
              0x4826,0x5807,0x28E0,0x38C1,0x08A2,0x1883                               //256 PLC
      };                                                     //CRC_Code[]数组就是一个余数表
          unsigned short int n_CrcCode16=0;
          unsigned short int LOCAIION=0;
          for(size_t i=0;i!=CodeLength;i++)
          {
              LOCAIION=(n_CrcCode16 & 0xff)^(CrcSrcCode[i] & 0xff);             //查表,事实上就是获取该余数在CRC_Code[]数组的中的位置

[1] [2]  下一页


本文关键字:C语言  PLC入门plc技术 - PLC入门