CRC检错技术原理

**

一、CRC检错原理

**
CRC(cyclic redundancy check/code):循环冗余检错技术/循环冗余校验码;

《计算机网络 第五版》—谢希仁所著的教材通过例子对循环冗余检验原理的原理说明如下:
在发送端,先把数据划分为组,假定每组k个比特。现假定待传送的数据M=101001(k=6)。CRC运算就是在数据M的后面添加供差错检测用的n位冗余码,然后构成一个帧发送出去,一共发送(k+n)位。在所要发送的数据后面增加n位的冗余码,虽然增大了数据传输的开销,但却可以进行差错检测。当传输可能出现错误时,付出这种代价往往是很值得的。

这n位冗余码可用以下方法得出。用二进制的模2运算进行乘M的运算,这相当于在M后面添加n个0。得到的(k+n)位的数除以收发双方事先商定的长度为(n+1)位除数P,得出的商是Q而余数是R(n位,比P少一位)。关于除数P下面还要介绍。在图1所示的例子中,M=101001(即k=6)。假定除数P=1103(即n=3)。经模2除法运算后的结果是:商Q=110101(这个商并没有什么用处),而余数R=001。这个余数R就作为冗余码拼接在数据M的后面发送出去。这种为了进行检错而添加的冗余码常称为帧检验序列FCS(Frame Check Sequence)。因此加上FCS后发送的帧是101001001(即),共有(k+n)位。
在这里插入图片描述
顺便说一下,循环冗余检验CRC和帧检验序列FCS并不是同一概念。CRC是一种检错方法,而FCS是添加在数据后面的冗余码,在检错方法上可以选用CRC,但也可以不选用CRC。

在接受端把接收到的数据以帧为单位进行CRC检验:把收到的每一个帧都除以同样的除数P(模2运算),然后检查得到的余数R。

如果在传输过程中无差错,那么经过CRC检验后得出的余数R肯定是0。但如果出现误码,那么余数R仍等于零的概率是非常非常小的(可以通过不太复杂的概率计算得出)。
  总之,在接收端对收到的每一帧经过CRC检验后,有以下两种情况:
  1)若得出的余数R=0,则判定这个帧没有差错,即接受(accept);
  2)若余数R!=0,则判定这个帧有差错,即丢弃(discard)。  
  一种较方便的方法时用多项式来表示循环冗余检验过程。在上面的例子中,用多项式 表示上面的除数P=1101(最高位对应于,最低位对应于)。多项式P(X)称为生成多项式。现在广泛使用的生成多项式P(X)有以下几种:
在这里插入图片描述
小结:

小结一下上述教材内容所提到的内容:

1)什么叫"模2运算"?
  通过一个例子的话我想能够在你脑子里形成清晰的概念。假如一个数k被任意的数除,那么它产生的余数必定是在[0,n)区间中。即x mod n ∈ [0, n)。模2运算也是符合这种理论的,即模2运算就是指结果只能是在[0,2)区间中取整数值的运算,显然"模2运算"就是指结果只能为0、1的特殊二进制运算。
  2)为什么"模2运算"属于特殊二进制运算,必须突出"特殊"二字?
  第一点,"模2运算"和"二进制运算"名字本身就不同,因此类比的时候使用"特殊"二字;第二点,两者的运算其实是有区别,"模2运算"既不进位也不退位,而"二进制运算"和"十进制运算"均需要进、退位。
  3)循环冗余检验只是数学检错技术中的一种,还有奇偶校检等数学手段。而且循环冗余检验并不能保证100%正确,只能说接近100%。

**

二、CRC检错实战

**
在这里插入图片描述
首先分析生成多项式,显然n=3,因此循环冗余码应为3位二进制数。生成多项式代表的二进制除数P=1001,发送的数据为101110,则真实的被除数为101110000。进行减模2运算(异或运算)如下:
在这里插入图片描述
于是得到FCS为011,因此发送数据实际为101110011(除以1001余数为0,读者可自行尝试)。注意到,在运算的时候,每次都会往后退一位,即第一位每次都是被消掉的。

	注意:计算机网络通信中,我们对生成多项式(除数)作了统一的标准,即针对不同的帧,发送端网卡添加不同的FCS,而接受端网卡知道相应帧该用CRC-16还是CRC-32来检错。

上代码:

`timescale  1ns/1ps
module CRC(
    input wire clk,
    input wire rstn,
    input wire req,
    input wire [5:0] i_data,
    input wire [3:0] i_crc,
    output reg [8:0] o_data_fcs,
    output reg o_vld
);
reg [5:0] i_data_r;//缓存
reg [3:0] i_crc_r;//缓存
reg start;
reg [9-4-1:0] data_middle_shift;
reg [3:0] fcs_r;
reg [5:0] count;

always @(posedge clk or negedge rstn ) begin
    if(~rstn)begin
        i_data_r<='b0;
        i_crc_r<='b0;
        start<='b0;
    end
    else if(req & ~start)begin
        i_data_r<=i_data;
        i_crc_r<=i_crc;
        start<='b1;
    end
    else if(start && o_vld)begin
        start<='b0;
    end
end

//利用移位寄存器实现模2运算输入
always @(posedge clk or negedge rstn ) begin
    if(~rstn)begin
        data_middle_shift<='b0;
    end
    else if(req)begin
        data_middle_shift<={i_data[1:0],3'b000};
    end
    else if(start && count!='b0)begin
        data_middle_shift<={data_middle_shift[3:0],1'b0};
    end
end
//控制异或运算次数
always @(posedge clk or negedge rstn ) begin
    if(~rstn)begin
        count<='b0;
    end
    else if(req)begin
        count<='d5;
    end
    else if(start&&count=='d0)begin
        count<='d5;
    end
    else if(start)begin
        count<=count-'b1;
    end

end

//模2运算
always @(posedge clk or negedge rstn ) begin
    if(~rstn)begin
        fcs_r<='b0;
    end
    else if(req)begin
        if(i_data[5])
            fcs_r<=i_data[5:2]^i_crc;
        else begin
            fcs_r<=i_data[5:2];
        end
    end
    else if(start)begin
        if(fcs_r[2])
            fcs_r<={fcs_r[2:0],data_middle_shift[4]}^i_crc_r;
        else begin
            fcs_r<={fcs_r[2:0],data_middle_shift[4]};
        end
    end
end

always @(posedge clk or negedge rstn ) begin 
    if(~rstn)begin
        o_vld<='b0;
    end
    else if(count=='b1 && start)begin
        o_vld<='b1;
    end
    else
        o_vld<='b0;
end

always @(posedge clk or negedge rstn ) begin
    if(~rstn)begin
        o_data_fcs<='b0;
    end
    else if(o_vld)begin
        o_data_fcs<={i_data_r,fcs_r[2:0]};
    end
    else
        o_data_fcs<=o_data_fcs;
end
endmodule

tb:

`timescale  1ns/1ps
module tb_crc();
reg clk;
reg rstn;
reg req;
reg [5:0] i_data;
reg [3:0] i_crc;
wire [8:0] o_data_fcs;
wire o_vld;
    
initial begin
	clk<=1;
	rstn=1;
    #(20)
	rstn=0;
	#100;
	rstn<=1;
end
always #10 clk=~clk;
    
initial begin
req<='b0;
i_data<=6'b101110;
i_crc<='b1001;
#(120) req<='b1;
#(20) req<='b0;
end
    
    

CRC cr_inst(
    .clk(clk),
    .rstn(rstn),
    .req(req),
    .i_data(i_data),
    .i_crc(i_crc),
    .o_data_fcs(o_data_fcs),
    .o_vld(o_vld)
);


endmodule

测试结果:计数到0输出crc校验码:101110011
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值