详细的文字解释可以参考这个小伙伴写的→详细解释看这里
1. “奇偶校验”
我们规定好,一串编码里1的个数是偶数个,那么这串编码里携带的信息就是对的,否则就是错的。(这里统一用偶校验为例)
我们可以在开头对这串编码加一位校验码实现奇偶校验。
我们想传输10010这串码,那么在传输的时候,就传010010,其中在开头的0就是校验位。(不用凑,1已经为偶数)
我们想传输10000这串码,那么在传输的时候,就传110000,其中在开头的1就是校验位。(凑个1,成偶数)
2. 汉明码检错原理
汉明码默认一串数据只错一位,所以检错纠错的个数都是1
在这里我们假设我们传输的信息是1234567,然后按一定的规则他们分成三组
分别是
P1:1,2,3,4
P2:2,4,5,6
P3:3,4 ,6,7
那么我们来看几种情况:
(1)如果只有第一组有数错误了,那肯定是1错了。
(2)如果第一第二组错了,而第三组没有错,那肯定是2错了。
(3)然后三组都错,那肯定是4错了。
这就是汉明码的检错原理了,我们找到错误的那个码,又因为二进制里面只有两个选项1和0,给错误的码改成相反的信息就完成了纠错了
3. 分组原理
上面是把七个数分成了三组,具体方法是把位置1234567(这里刚好和值是一样的,不要理解错了,是位置!位置!位置!)换成二进制
P0第一组就是二进制低位为1的,P1第二组就是第二位为1的,后面类似....
(先把校验位加进去原数据,才能得到编码分组)
4. 汉明码编码
下面的内容需要记一记,就是汉明码=数据码+校验码。
记1:校验码个数k→
假如有n个数据码,k个校验码,那么码错误的位置就会有n+k个,再加上一个没有错误的可能性,就有n+k+1种可能性。
那么k的个数只要满足 即可(其实就是记这个公式。上面7个数,就是2^4=>=7+4+1=12,其实是需要4个校验码的)
记2:校验码位置→2的次方位置,2^0,2^1,2^3......,也就是1/2/4/8/16.........
就是一串数据,校验位是固定的,我们的有效信息也是固定的
1=p0,2=p1,3=p2......
记3:分完组后每个组里面只有一个校验码
除了这个校验码,外面的都是有效信息
(先把校验位加进去原数据,才能得到编码分组)
5. 汉明码解码
我们都知道怎么分组了,也知道校验码和信息的具体位置了,只要看看接收的数据有没有错就行了。(偶校验为例)
将分组按大到小 P3/P2/P1,排列,然后看每个组的有效信息是不是都是偶数,不是就是1,是的话就是0。然后得到下图
然后根据最开始说的,就可以判断出哪个数是错了的,再取反纠正即可。
6.FPGA代码
因为我们的传输主要是以字节为单位,所以规定的输入是8bit(一个字节)
2^4>=8+4+1,所以有4个校验码,得到的编码后的数据是12位的。
(然后注意,代码中的位置是从0开始的,与上面位置1开始的不一样哦,注意)
编码部分:
发送data={0,1,2,3,4,5,6,7} 8bit数据
8变12,对应的应该是encode={p0,p1,0,1,p2,2,3,4,p3,5,6,7,8}
所以分组的时候对应的位置应该是{3,5,6,7,9,10,11,12}(位置从1开始的)
然后按二进制分类,得到p0 = 1,2,4,5,7(位置),对应的是data[0,1,3,4,6]
p1,p2,p3类似
module hamming_encoder(clk, rst_n, wren, data, hc_out);
input clk, rst_n;
input wren;
input [7:0] data;
output reg [11:0] hc_out;
wire p0, p1, p2, p3;
assign p0 = data[6] ^ data[4] ^ data[3] ^ data[1] ^ data[0];
assign p1 = data[6] ^ data[5] ^ data[3] ^ data[2] ^ data[0];
assign p2 = data[7] ^ data[3] ^ data[2] ^ data[1];
assign p3 = data[7] ^ data[6] ^ data[5] ^ data[4];
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)
hc_out <= 0;
else if(wren)
hc_out <= {data[7:4], p3, data[3:1],p2, data[0], p1, p0};
else
hc_out <= 0;
end
endmodule
译码部分:
8变12,对应的应该是encode={p0,p1,0,1,p2,2,3,4,p3,5,6,7,8}
所以按照1-12分组,就会得到g0_error = {1,3,5,7,9,11}(位置),对应的是encode=[0,2,4,6,8,10],
g1_error...... 类似
然后根据排列组合,把错纠正过来就OK了
module hamming_decoder(clk, rst_n, rden, q, hc_in);
input clk, rst_n;
input rden;
output reg [7:0] q;
input [11:0] hc_in;
wire g0_error, g1_error, g2_error,g3_error;
assign g0_error = hc_in[10] ^ hc_in[8] ^ hc_in[6] ^ hc_in[4] ^ hc_in[2] ^ hc_in[0];
assign g1_error = hc_in[10] ^ hc_in[9] ^ hc_in[6] ^ hc_in[5] ^ hc_in[2] ^ hc_in[1];
assign g2_error = hc_in[11] ^ hc_in[6] ^ hc_in[5] ^ hc_in[4] ^ hc_in[3];
assign g3_error = hc_in[11] ^ hc_in[10] ^ hc_in[9] ^ hc_in[8] ^ hc_in[7];
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[11:8], hc_in[6:4], hc_in[2]};
4'b0001 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
4'b0010 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
4'b0011 : q <= {hc_in[11:8], hc_in[6:4], ~hc_in[2]};
4'b0100 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
4'b0101 : q <= {hc_in[11:8], hc_in[6:5], ~hc_in[4], hc_in[2]};
4'b0110 : q <= {hc_in[11:8], hc_in[6], ~hc_in[5], hc_in[4], hc_in[2]};
4'b0111 : q <= {hc_in[11:8], ~hc_in[6], hc_in[5], hc_in[4], hc_in[2]};
4'b1000 : q <= {hc_in[11:8], hc_in[6], hc_in[5], hc_in[4], hc_in[2]};
4'b1001 : q <= {hc_in[11:9], ~hc_in[8], hc_in[6:4], hc_in[2]};
4'b1010 : q <= {hc_in[11:10], ~hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};
4'b1011 : q <= {hc_in[11], ~hc_in[10], hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};
4'b1100 : q <= {~hc_in[11], hc_in[10], hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};
default : q <= 0;
endcase
else
q <= 0;
end
endmodule
仿真结果: