目錄
- 格雷碼的介紹
- 二進位制碼轉化為格雷碼
- 格雷碼轉化為二進位制碼
- verilog實現程式碼
格雷碼的介紹
在一組數的編碼中,若任意兩個相鄰的程式碼只有一位二進位制數不同,則稱這種編碼為格雷碼(Gray Code),另外由於最大數與最小數之間也僅一位數不同,即“首尾相連”,因此又稱迴圈碼或反射碼。
在數字系統中,常要求程式碼按一定順序變化。例如,按自然數遞增計數,若採用8421碼,則數0111
變到1000
時四位均要變化,而在實際電路中,4位的變化不可能絕對同時發生,則計數中可能出現短暫的其它程式碼(1100、1111
等)。在特定情況下可能導致電路狀態錯誤或輸入錯誤。使用格雷碼可以避免這種錯誤。
二進位制碼轉化為格雷碼
二進位制碼轉換成二進位制格雷碼,其法則是保留二進位制碼的最高位作為格雷碼的最高位,而次高位格雷碼為二進位制碼的高位與次高位相異或,而格雷碼其餘各位與次高位的求法相類似。
假設有n位二進位制數:
n位二進位制數 | Bn-1 | Bn-2 | Bn-3 | ... | B1 | B0 |
---|
其轉化位相應n位格雷碼的轉化法則為:
n位格雷碼 | Gn-1 | Gn-2 | Gn-3 | ... | G1 | G0 |
---|---|---|---|---|---|---|
轉化規則 | Bn-1 | Bn-1^Bn-2 | Bn-2^Bn-3 | ... | B2^B1 | B1^B0 |
在verilog
中,假設有 logic [n-1:0] bin; logic [n-1:0] grey
;
則有:
bin | Bn-1 | Bn-2 | Bn-3 | ... | B1 | B0 |
---|---|---|---|---|---|---|
bin>>1 | 0 | Bn-1 | Bn-2 | Bn-3 | ... | B1 |
grey | Bn-1^0 | Bn-1^Bn-2 | Bn-2^Bn-3 | ... | B2^B1 | B1^B0 |
grey | Bn-1 | Bn-1^Bn-2 | Bn-2^Bn-3 | ... | B2^B1 | B1^B0 |
因為Bn-1^0=Bn-1,所以在verilog中,我們可以用下面的幾行程式碼,得到二進位制編碼到格雷碼的轉化:
logic [n-1:0] bin;
logic [n-1:0] grey
assign grey = bin ^ (bin>>1);
格雷碼轉化為二進位制碼
從前面二進位制碼轉化為格雷碼法則,我們知道
Gn-i=Bn-i+1^Bn-i
則有
Bn-i+1^Gn-i = Bn-i+1 ^ Bn-i+1 ^ Bn-i
Bn-i+1 ^ Gn-i = 0 ^ Bn-i-1= Bn-i
所以格雷碼轉化為二進位制碼的規則為:
n位二進位制 | Bn-1 | Bn-2 | Bn-3 | ... | B1 | B0 |
---|---|---|---|---|---|---|
轉化規則 | Gn-1 | Gn-2^Bn-1 | Gn-3^Bn-2 | ... | G1^B2 | B0^B1 |
在verilog中我們可以用一個generate塊內迴圈實現轉換
//從次高位到0,二進位制的高位和次高位格雷碼相異或
genvar i;
generate
for(i = 0; i <= DATA_WIDTH-2; i = i + 1)
begin:
assign bin[i] = bin[i + 1] ^ grey[i];
end
endgenerate
verilog實現程式碼
檔名稱:code4_41.v
`timescale 1ns/1ps
module grey_tb;
logic clk=0;
always #5 clk = ~clk;
initial begin
$display("start a clock pulse");
$dumpfile("grey.vcd");
$dumpvars(0, grey_tb);
#300 $finish;
end
logic [7:0] bin;
logic [7:0] grey;
logic [7:0] bin2;
logic [7:0] bin_1=0;
logic [7:0] grey_1;
logic [7:0] bin2_1;
initial begin
// 重複執行10次隨機數生成過程
repeat(10) begin
@(posedge clk) begin
bin <= $random();
end
end
// 重複執行32次的迴圈,用於對bin_1進行自增操作
repeat(32) begin
@(posedge clk) begin
bin_1 <= bin_1+1;
end
end
end
bin2grey #(.DATA_WIDTH(8)) bin2grey_inst(.bin(bin),.grey(grey));
grey2bin #(.DATA_WIDTH(8)) grey2bin_inst(.grey(grey),.bin(bin2));
bin2grey #(.DATA_WIDTH(8)) bin2grey_inst1(.bin(bin_1),.grey(grey_1));
grey2bin #(.DATA_WIDTH(8)) grey2bin_inst1(.grey(grey_1),.bin(bin2_1));
endmodule
//二進位制轉格雷碼
module bin2grey
#(
parameter DATA_WIDTH=8
)
(
input wire [DATA_WIDTH-1:0] bin,
output logic [DATA_WIDTH-1:0] grey
);
assign grey = bin ^(bin>>1);
endmodule
//格雷碼轉二進位制碼
module grey2bin
#(
parameter DATA_WIDTH=8
)
(
input wire [DATA_WIDTH-1:0] grey,
output logic [DATA_WIDTH-1:0] bin
);
assign bin[DATA_WIDTH-1] = grey[DATA_WIDTH-1];
genvar i;
generate
for(i=DATA_WIDTH-2;i>=0;i=i-1) begin
assign bin[i] = bin[i+1] ^ grey[i];
end
endgenerate
endmodule
在vscode中執行以下命令,編譯code,開啟波形檔案:
iverilog -o myrun -g 2012 code4_42.v
vvp myrun
gtkwave grey.vcd
可以看到二進位制碼先轉化為格雷碼,再轉回二進位制碼,得到期望的值。而且相鄰數的格雷碼確實是只差1位數。