CRC循环校验码的系统仿真及其应用

简介: CRC循环校验码的系统仿真及其应用

微信图片_20221017094920.png一、CRC校验码的介绍

CRC即循环冗余校验码,是数据通信领域中最常用的一种检错校验码,其特征是信息字段和校验字段的长度可以任意选定,循环冗余检查是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性

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

二、CRC校验码原理

CRC校验码的基本思想是先在要发送的帧后面附加上一个数(这个就是用来校验的校验码,但要注意这里的数也是二进制序列),生成一个新帧发送的接收端,并且这个附加的数不是随意的,它要使所产生的新帧能与发送端和接收端共同选定的某个特定数整除,这里的除不是直接采用二进制除法,而是采用模二除法。到达接收端的后,再把接收到的新帧除以这个选定的数。因为在发送端发送数据之前就已经通过附加一个数,做了去余处理,也就是已经整除了。所以结果应该是没有余数的。如果有余数,则表示该帧在传输过程中出现了差错。

具体来说,CRC校验原理可以分为以下几个步骤。

选择(可以随机选择也可以按照标准选择)一个用于在接收端进行校验时,对接收的帧进行除法运算的除数(是二进制比特串,通常是以多项方式表示,所以CRC又称多项式编码方法,这个多项式也称为“生成多项式”

看所选定的除数二进制位数(假设为k位),然后在要发送的数据帧(假设为m位)后面加上k-1位“0°”之后用这个加了k-1个”0”的新帧(一共是m+k-1位),以模二除法的方式除以上面这个除数,所得到的余数(也是二进制比特串)就是该帧的CRC校验码,也称为FCS(帧校验序列),要注意的是,余数的位数一定是要比除数位数只能少一位,哪怕前面位是0,甚至全是0(附带好整除时)也不能省略。

把这个校验码附加在原数据帧(就是m位的帧,注意不是在后面形成的m+k-1的帧)后面,构建一个新帧发送到接收端,最后在接收端再把这个新帧以“模二除法”方式除以前面选择的除数,如果没有余数,则表明该帧在传输过程中没有出错,否则就是出现了差错。

从上面可以看出,CRC校验中有两个关键点: 一是要预先确定一个发送端和接收端用来作为除数的二进制比特串(或多项式);二是把原始帧与上面选定的除数进行二进制除法运算,计算出FCS。前者可以随机选择,也可按国际上通行的标准选择,但最高位和最低位必须均为“1”,如在IBM的SDLC(同步数据链路控制)规程中使用的CRC-16也就是这个除数-共是17位)生成多项式g(x)=x9+x5+x2 +1(对应的二进制比特串为11000000000000101)而在ISO HDLC (高级数据链路控制)规程、ITU的SDLC X.25、V.34. V.41、V.42等中使用CCITT-16生成多项式g(x)=x16+x15+x2+1(对应的二进制比特串为11000000000100001)。

三、CRC校验码的三种常见实现方法

1、按位计算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^=0x1021;}   /* 余式CRC乘以2再求CRC  */
        else crc*=2;
if((*ptr&i)!=0) crc^=0x1021;                /* 再加上本位的CRC */
    }
    ptr++;
  }
  return(crc);
}

2、 按字节计算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,
    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, 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=(uchar) (crc/256);    /* 以8位二进制数的形式暂存CRC的高8位 */
    crc<<=8;              /* 左移8位,相当于CRC的低8位乘以  */
    crc^=crc_ta[da^*ptr];   /* 高8位和当前字节相加后再查表求CRC ,再加上以前的CRC */
    ptr++;
  }
  return(crc);
}

3、 按半字节计算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=((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);
}

4、三种方法的比较

以上介绍的三种求CRC的程序,按位求法速度较慢,但占用最小的内存空间;按字节查表求CRC的方法速度较快,但占用较大的内存;按半字节查表求CRC的方法是前两者的均衡,即不会占用太多的内存,同时速度又不至于太慢,比较适合8位小内存的单片机的应用场合。以上所给的C程序可以根据各微处理器编译器的特点作相应的改变,比如把CRC余式表放到程序存储区内等。

四、CRC-16检验码检错性能仿真

这部分我是使用matlab的Simulink仿真实现的。使用simulink仿真CRC-16检验码在二进制对称信道中的检错性能。每一帧含有的消息比特数为64,二进制对称信道采用16-QAM调制,Er/E0 的范围为0—10dB。

其实现步骤如下。

1、建立仿真模型。

微信图片_20221017095102.png

根据需要建立的仿真模型如图4.1所示。

2、子系统模型如图4.2所示

微信图片_20221017095104.png

3、运行需要的matlab调用代码

EbN0=0:10;
% ber=berawgn(EbN0,"qam",16);
ber=berawgn(EbN0,"qam",16); 
for i=1:length(EbN0)
    BER=ber(i);
    x= sim('modal_CRC');
    pmissed(i)=x.MissedFrame(end)/length(x.MissedFrame);
end
semilogy(EbN0,pmissed,'-ko');
title('图4.3  CRC-16检错性能');
xlabel('Eb/N0');ylabel('漏检概率');
axis([0 8 10.^(-6) 10.^(-3)]);
grid on

berawgn(EbN0,"qam",16)这个函数构建了非编码AWGN信道 ,并且会返回一个AWGN信道上一致检测到的未编码qam的ber

4、检错性能分析

通过分析图4.3可以发现不管信道的干扰怎么变化,CRC检测发生错误判决的比例都小于10-4 。因此,CRC编码广泛的应用于移动通信系统中,用于实现自动请求重传(ARQ)功能。

微信图片_20221017095222.png

图4.3仿真效果图

五、51单片机串口通信的校验

从第四部分对CRC的性能检错分析可以看出CEC检错能力是非常强大的。从三部分可以看出按位求法速度较慢,但占用最小的内存空间。我做的是两个单片机之间进行串行通信,用的89c52.通过按主机p27口"启动键",主机向从机发送一个四位数据,LED显示。从机经过CRC校验,如果接收到正确数据,与其相连的LED显示所接收的数据。如果经校验后接收错误,则四位LED显示0xFFFF。

实现步骤如下。

1、硬件电路如下所示

微信图片_20221017095225.png

2、程序CRC算法实现部分如下所示。

从第三部分的CRC三种实现方式中我选择的第一种,因为51的内存太小了,放不下。造成的后果就是这个校验的速度特别慢,这个设计最后的仿真效果也不是特别好。

//************************进行数据校验****************************************//
int chkcrc(uchar *buf,uchar len)
{
  uint strcrc;
   strcrc=getcrc(buf,len);   //生成接收数据的CRC码
   if(((0xff&buf[len])==(0xff&(strcrc/256)))&&((0xff&buf[len+1])==(0xff&(strcrc%256))))
                           //接收的CRC码和生成的CRC码进行比较
     return(0);
   else
             return(-1);
 }
void tongxin()
{
uchar i = 0;
uchar tmp;
/* 发送呼叫信号CALL并接收应答信息,如果没有接收到从机准备好的信号,则重新发送呼叫帧 */
while(tmp!=OK)
{
/* 发送呼叫信号CALL */
TI = 0;
SBUF = CALL;
while(!TI);
TI = 0;
/* 接收从机应答 */
RI = 0;
while(!RI);
tmp = SBUF;
RI = 0;
}
}
/*串口通信程序 */
void tongxin()
{
uchar tmp=0;
init_serial();
        EA = 0; // 关闭所有中断
       /* 如果接收到的数据不是CALL,则继续等待 */
while (tmp!=CALL)
{
RI = 0;
while(!RI)
tmp = SBUF;
RI = 0;
}
/* 发送OK信号,表示从机可以接收数据 */
TI = 0;
SBUF = OK;
while(!TI);
TI = 0;
/* 数据接收 */
err = recvdata(buf); // 校验失败返回1,接收成功返回0
                        if(err==1)
    display_f();
                        if(err==0)
             display();
}

3、仿真效果显示

微信图片_20221017095420.png




相关文章
|
6天前
|
编解码 算法
m基于码率兼容打孔LDPC码oms最小和译码算法的LDPC编译码matlab误码率仿真
m基于码率兼容打孔LDPC码oms最小和译码算法的LDPC编译码matlab误码率仿真
41 0
|
5天前
奇偶校验,CRC循环冗余校验,海明码校验
奇偶校验,CRC循环冗余校验,海明码校验
11 0
|
6天前
|
编解码 算法 索引
m基于码率兼容打孔LDPC码ms最小和译码算法的LDPC编译码matlab误码率仿真
m基于码率兼容打孔LDPC码ms最小和译码算法的LDPC编译码matlab误码率仿真
25 0
|
7月前
CRC循环冗余码计算
CRC循环冗余码计算
62 0
|
7月前
|
索引
海明校验码检错和纠错的工作原理
海明校验码检错和纠错的工作原理
78 0
|
10月前
|
算法 异构计算
m基于双PN序列的数据帧检测,帧同步verilog实现,含testbench
m基于双PN序列的数据帧检测,帧同步verilog实现,含testbench
270 0
|
10月前
【软考学习7】数据校验——海明校验码、循环校验码、奇偶校验码
【软考学习7】数据校验——海明校验码、循环校验码、奇偶校验码
276 0
|
11月前
|
算法 C语言
LabVIEW实现CRC校验
CRC(循环冗余校验),是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。
LabVIEW实现CRC校验
|
11月前
循环码的编码、译码与循环冗余校验
循环码的编码、译码与循环冗余校验
98 0
循环码的编码、译码与循环冗余校验
|
11月前
|
算法 异构计算
m基于FPGA的CRC循环冗余校验系统verilog实现,包含testbench
m基于FPGA的CRC循环冗余校验系统verilog实现,包含testbench
203 0