基于FPGA(Verilog)的CRC16校验码的原理与计算(附带例程)

  • 什么是CRC校验

循环校验码(CRC码):是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。

这个校验方式的根本思想是在发送数据的后面拼接上一些额外的数据位,使得这个拼接之后的数据可以被一个固定的数模2整除(这里的模2整除是一种区别于普通的除法的运算方法,也不难理解),之后将数据发送……接收端同样将整个拼接后的数据与之前确定的固定的数据做模2除法,若能整除,则说明传输过程没有出错,若不能整除,则可以根据余数判断是哪一位发生了错误。

  • 生成CRC码的基本原理

任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。

标准CRC生成多项式如下表:

   名称          生成多项式              简记式*   标准引用

   CRC-4         x4+x+1                  3         ITU G.704

   CRC-8         x8+x5+x4+1              0x31                   

   CRC-8         x8+x2+x1+1              0x07                   

   CRC-8         x8+x6+x4+x3+x2+x1       0x5E

   CRC-12        x12+x11+x3+x+1          80F

   CRC-16        x16+x15+x2+1            8005      IBM SDLC    (最常用的CRC16校验)

CRC16-CCITT  x16+x12+x5+1   1021   ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS

   CRC-32      x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS

   CRC-32c     x32+x28+x27+...+x8+x6+1 1EDC6F41     SCTP

CRC校验是前面几段数据内容的校验值,为一个16位数据,发送时,低8位在前,高8为最后。

例如:信息字段代码为: 1011001,校验字段为:1010。

发送方:发出的传输字段为:  1 0 1 1 0 0 1 1 0 10

                          信息字段       校验字段

接收方:使用相同的计算方法计算出信息字段的校验码,对比接收到的实际校验码,如果相等及信息正确,不相等则信息错误;或者将接受到的所有信息除多项式,如果能够除尽,则信息正确

  • CRC-16校验码计算方法

常用查表法和计算法。计算方法一般都是:
(1)、预置1个16位的寄存器为十六进制FFFF(即全为1),称此寄存器为CRC寄存器;
(2)、把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低
       8位相异或,把结果放于CRC寄存器,高八位数据不变;
(3)、把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
(4)、如果移出位为0:重复第3步(再次右移一位);如果移出位为1,CRC寄存器与多

    项式A001(1010 0000 0000 0001)进行异或;
(5)、重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
(6)、重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
(7)、将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低
       字节进行交换;
(8)、最后得到的CRC寄存器内容即为:CRC码。

以上计算步骤中的多项式A001是(CRC-16)8005按位颠倒后的结果。

查表法是将移位异或的计算结果做成了一个表,就是将0~256放入一个长度为16位的寄存器中的低八位,高八位填充0,然后将该寄存器与多项式0XA001按照上述3、4步骤,直到八位全部移出,最后寄存器中的值就是表格中的数据,高八位、低八位分别单独一个表。

  • Verilog实现程序

该程序表示计算一个字节的校验值,实际收到多少个字节数,就循环调用该计算程序多少次

always@(posedge clk)
begin
    if(signal_start_status == 1)//表收到一个完整的字节
		begin
			CRC = CRC ^ data_1;
			signal_CRC_start <= 1;//该字节校验值计算开始标志
			cnt_data <= cnt_data + 1;//收到字节数+1
			
		end
    else
        if(cnt_reg == 8)//该字节的8位校验值全部计算完
		begin
                        signal_CRC_start <= 0;
			cnt_reg <= 0;
		end
        else
		if(signal_CRC_start == 1)
                        begin
			        for(i=7;i>=0;i=i-1)//对8位依次计算
					begin
						cnt_reg = cnt_reg +1;
						if(CRC[0] == 0)
                                                    begin
						    CRC = CRC>>1;
						    end
                                                else
						    if(CRC[0] == 1)
							begin
							CRC = (CRC>>1)^ data_buffer;
							end
                                        end
                        end
end

 

 

 

 

 

你可能感兴趣的:(fpga)