實驗簡述:
本實驗的目的是實現漢明糾錯碼的編碼和解碼
一、漢明碼簡介
漢明碼,是在電信領域的一種線性調試碼,以發明者理查德 衛斯理 漢明的名字命名。漢明碼在傳輸的消息流中插入驗證碼,當計算機存儲或移動數據時,可能會產生數據位錯誤,以偵測并更正單一比特錯誤。由于漢明編碼簡單,他們被廣泛應用于內存。
與其他的錯誤校驗碼類似,漢明碼也利用了奇偶校驗位的概念,通過在數據位后面增加一些比特,可以驗證數據的有效性。利用一個以上的校驗位,漢明碼不僅可以檢驗數據是否有效,還能在數據出錯的情況下指明錯誤的位置。(漢明碼可以檢測兩位錯誤,糾正一位錯誤)。
二、編碼規則
理解漢明碼首先要理解奇偶校驗,奇校驗就是在一串編碼里增加一位校驗位使這一串編碼里的1的個數位奇數。偶校驗同理,使編碼里1的個數為偶數。
漢明碼的編碼位數n與糾錯碼的位數k的關系:2^k >= n+k+1。這里給出常用的n和k的值:
n |
1 |
2-4 |
5-11 |
12-26 |
27-57 |
58-120 |
k |
2 |
3 |
4 |
5 |
6 |
7 |
我們將糾錯碼加入到相應的編碼里,糾錯碼的位置必須在2^n位置上。以10101100為例進行編碼。這個序列為8位,需要4個糾錯碼。
我們先將序列從1到8編號
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
然后將糾錯碼(p1,p2,p3,p4)加到這個序列里 的2^n的位置,并用二進制重新編號
0001 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
1000 |
1001 |
1010 |
1011 |
1100 |
p1 |
p2 |
1 |
p3 |
0 |
1 |
0 |
p4 |
1 |
1 |
0 |
0 |
然后我們要求出p1,p2,p3,p4的值,先將上面的序列分組編號為xxx1的分為一組,xx1x的分為一組,x1xx的分為一組,1xxx的分為一組:
xxx1:p1,1,0,0,1,0
xx1x:p2,1,1,0,1,0
x1xx:p3,0,1,0,0
1xxx:p4,1,1,0,0
我們采用偶校驗,所以p1 = 1,p2 = 1, p3 = 1, p4 = 0。這樣我們就得到了10101100的漢明碼111101001100。
那么漢明碼是如何來糾錯的呢?
我們將p4,p3,p2,p1按這個順序排列得到0111,這個就是出錯的位數,由于是二進制傳輸,所以就將相應位取反就可以得到正確的序列了。
三、FPGA實現
對于p1,p2,p3,p4的計算在用fpga實現時只需進行按位異或就行。輸入數據位8位,需要四個糾錯位。
1、頂層架構

信號說明:
信號 |
功能 |
說明 |
clk |
工作時鐘 |
外部輸入 |
rst_n |
系統復位 |
外部輸入 |
data |
輸入數據 |
外部輸入 |
wren |
寫使能 |
外部輸入 |
rden |
讀使能 |
外部輸入 |
q |
輸出數據 |
輸出 |
hc_out |
經過漢明編碼后輸出 |
輸出 |
hc_in |
輸入的漢明碼 |
外部輸入 |
頂層代碼:

2、 編碼模塊
編碼模塊只需將分組之后的每一組數據(不包括p)按位異或后賦值給p就可以。
編碼模塊代碼:

3、解碼模塊
解碼模塊只需判斷哪位出錯,然后取反,并將糾錯位刪除即可。
解碼模塊代碼:
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
|
四、仿真驗證
我們用$random系統函數產生的隨機數來作為編碼模塊數據,用$random系統函數產生的隨機數來將hc_out的哪一位取反來模擬噪聲。并判斷輸入的數據和輸出的數據是否相等,以驗證糾錯功能。用$display和$error系統函數來生成報告。
測試文件代碼:
module humming_coder12_8_tb;
reg clk, rst_n;
reg [7:0] data;
reg rden, wren;
wire [11:0] hc_out;
reg [11:0] hc_in;
wire [7:0] q;
reg [7:0] 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[i] = hc_out[i];
else
hc_in[i] = ~hc_out[i];
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
生成的報告,我們可以看到錯誤的數據可以被修改成原來正確的數據,證明我們的編碼解碼模塊功能正確。