明德扬吴老师 发表于 2020-3-20 09:59:57

基于FPGA的汉明码编码解码设计

实验简述      本实验的目的是实现汉明纠错码的编码和解码
1.1汉明码简介

    汉明码,是在电信领域的一种线性调试码,以发明者理查德 卫斯理 汉明的名字命名。汉明码在传输的消息流中插入验证码,当计算机存储或移动数据时,可能会产生数据位错误,以侦测并更正单一比特错误。由于汉明编码简单,他们被广泛应用于内存。
      与其他的错误校验码类似,汉明码也利用了奇偶校验位的概念,通过在数据位后面增加一些比特,可以验证数据的有效性。利用一个以上的校验位,汉明码不仅可以检验数据是否有效,还能在数据出错的情况下指明错误的位置。(汉明码可以检测两位错误,纠正一位错误)。


1.2编码规则

    理解汉明码首先要理解奇偶校验,奇校验就是在一串编码里增加一位校验位使这一串编码里的1的个数位奇数。偶校验同理,使编码里1的个数为偶数。
    汉明码的编码位数n与纠错码的位数k的关系:2^k >= n+k+1。这里给出常用的n和k的值:

n12-45-1112-2627-5758-120
k234567

      我们将纠错码加入到相应的编码里,纠错码的位置必须在2^n位置上。以10101100为例进行编码。这个序列为8位,需要4个纠错码。我们先将序列从1到8编号

12345678
10101100

    然后将纠错码(p1,p2,p3,p4)加到这个序列里 的2^n的位置,并用二进制重新编号

000100100011010001010110011110001001101010111100
p1p21p3010p41100

    然后我们要求出p1,p2,p3,p4的值,先将上面的序列分组编号为xxx1的分为一组,xx1x 的分为一组,x1xx的分为一组,1xxx的分为一组:
xxx1:p1,1,0,0,1,0xx1x:p2,1,1,0,1,0x1xx:p3,0,1,0,01xxx:p4,1,1,0,0
   我们采用偶校验,所以p1 = 1,p2 = 1, p3 = 1, p4 = 0。这样我们就得到了10101100的汉明码111101001100。
      那么汉明码是如何来纠错的呢?
      我们将p4,p3,p2,p1按这个顺序排列得到0111,这个就是出错的位数,由于是二进制传输,所以就将相应位取反就可以得到正确的序列了。

1.3FPGA实现      对于p1,p2,p3,p4的计算在用fpga实现时只需进行按位异或就行。输入数据位8位,需要四个纠错位。

1.3.1 顶层架构



信号功能说明
clk工作时钟外部输入
rst_n系统复位外部输入
data输入数据外部输入
wren写使能外部输入
rden读使能外部输入
q输出数据输出
hc_out经过汉明编码后输出输出
hc_in输入的汉明码外部输入


   顶层代码

module humming_coder12_8(clk, rst_n, data, q, rden, wren, hc_out, hc_in);
    input clk, rst_n;    input data;    output q;    input rden, wren;    output hc_out;    input hc_in;
    hamming_encoder HE(      .clk(clk),       .rst_n(rst_n),       .wren(wren),       .data(data),       .hc_out(hc_out)    );
    hamming_decoder HD(      .clk(clk),       .rst_n(rst_n),       .rden(rden),       .q(q),       .hc_in(hc_in)    );
endmodule


1.3.2 编码模块

      编码模块只需将分组之后的每一组数据(不包括p)按位异或后赋值给p就可以

      编码模块代码

module hamming_encoder(clk, rst_n, wren, data, hc_out);
    input clk, rst_n;    input wren;    input data;    output reg hc_out;
    wire p0, p1, p2, p3;
    assign p0 = data ^ data ^ data ^ data ^ data;    assign p1 = data ^ data ^ data ^ data ^ data;    assign p2 = data ^ data ^ data ^ data;    assign p3 = data ^ data ^ data ^ data;
    always @ (posedge clk or negedge rst_n)begin      if(!rst_n)            hc_out <= 0;      else if(wren)            hc_out <= {data, p3, data,p2, data, p1, p0};      else                hc_out <= 0;    end
endmodule



1.3.3解码模块

    解码模块只需判断哪位出错,然后取反,并将纠错位删除即可

    解码模块代码

module hamming_decoder(clk, rst_n, rden, q, hc_in);
    input clk, rst_n;    input rden;    output reg q;    input hc_in;
    wire g0_error, g1_error, g2_error,g3_error;
    assign g0_error = hc_in ^ hc_in ^ hc_in ^ hc_in ^ hc_in ^ hc_in;    assign g1_error = hc_in ^ hc_in ^ hc_in ^ hc_in ^ hc_in ^ hc_in;    assign g2_error = hc_in ^ hc_in ^ hc_in ^ hc_in ^ hc_in;    assign g3_error = hc_in ^ hc_in ^ hc_in ^ hc_in ^ hc_in;
    always @ (posedge clk or negedge rst_n)begin      if(!rst_n)            q <= 0;      else if(rden)            case ({g3_error, g2_error, g1_error, g0_error})                4'b0000 :   q <= {hc_in, hc_in, hc_in};                4'b0001 :   q <= {hc_in, hc_in, hc_in};                4'b0010 :   q <= {hc_in, hc_in, hc_in};                4'b0011 :   q <= {hc_in, hc_in, ~hc_in};                4'b0100 :   q <= {hc_in, hc_in, hc_in};                4'b0101 :   q <= {hc_in, hc_in, ~hc_in, hc_in};                4'b0110 :   q <= {hc_in, hc_in, ~hc_in, hc_in, hc_in};                4'b0111 :   q <= {hc_in, ~hc_in, hc_in, hc_in, hc_in};                4'b1000 :   q <= {hc_in, hc_in, hc_in, hc_in, hc_in};                4'b1001 :   q <= {hc_in, ~hc_in, hc_in, hc_in};                4'b1010 :   q <= {hc_in, ~hc_in, hc_in, hc_in, hc_in};                4'b1011 :   q <= {hc_in, ~hc_in, hc_in, hc_in, hc_in, hc_in};                4'b1100 :   q <= {~hc_in, hc_in, hc_in, hc_in, hc_in, hc_in};                default :   q <= 0;            endcase      else            q <= 0;    end
endmodule


仿真验证

    我们用$random系统函数产生的随机数来作为编码模块数据,用$random系统函数产生的随机数来将hc_out的哪一位取反来模拟噪声。并判断输入的数据和输出的数据是否相等,以验证纠错功能。用$display和$error系统函数来生成报告。

      测试文件代码

module humming_coder12_8_tb;
    reg clk, rst_n;    reg data;    reg rden, wren;    wire hc_out;    reg hc_in;    wire q;
    reg temp1, temp2;
    humming_coder12_8 DUT(      .clk(clk),       .rst_n(rst_n),       .data(data),       .wren(wren),       .q(q),       .rden(rden),       .hc_out(hc_out),       .hc_in(hc_in)    );
    integer pn, i;
    initial begin      pn = 0;      hc_in = 0;
      forever begin            @ (posedge clk)            pn = {$random} %12;            #1            for (i=0; i<12; i=i+1) begin                if (i!= pn)                  hc_in = hc_out;                else                  hc_in = ~hc_out;            end      end    end
    always @ (posedge clk)    begin      temp1 <= data;      temp2 <= temp1;    end
    always @ (*)    begin      if (wren) begin            #1            if (temp2 == q)                $display("OK:time=%0t data=%0d q=%0d", $time, temp2, q);            else                $error("ERROR:time=%0t data=%0d q=%0d", $time, temp2, q);      end    end
    initial begin      clk = 1;      rst_n = 0;      data = 0;      rden = 0;      wren = 0;
      #200      @ (posedge clk)      rst_n = 1;
      #200      forever begin            @ (posedge clk)            wren = 1;            data = {$random} % 9'b10000_0000;            @ (posedge clk)            wren = 1;            data = {$random} % 9'b10000_0000;            rden = 1;      end    end
    always #10 clk = ~clk;
    initial #5000 $stop;
endmodule


    生成的报告,我们可以看到错误的数据可以被修改成原来正确的数据,证明我们的编码解码模块功能正确


页: [1]
查看完整版本: 基于FPGA的汉明码编码解码设计