格雷碼原理
格雷碼是一個叫弗蘭克*格雷的人在1953年發明的,最初用於通信。格雷碼是一種循環二進制碼或者叫作反射二進制碼。格雷碼的特點是從一個數變為相鄰的一個數時,只有一個數據位發生跳變,由於這種特點,就可以避免二進制編碼計數組合電路中出現的亞穩態。格雷碼常用於通信,FIFO或者RAM地址尋址計數器中。
如二進制計數編碼從0到F的計數過程如下:
十進制 |
二進制 |
格雷碼 |
十進制 |
二進制 |
格雷碼 |
0 |
0000 |
0000 |
8 |
1000 |
1100 |
1 |
0001 |
0001 |
9 |
1001 |
1101 |
2 |
0010 |
0011 |
10 |
1010 |
1111 |
3 |
0011 |
0010 |
11 |
1011 |
1110 |
4 |
0100 |
0110 |
12 |
1100 |
1010 |
5 |
0101 |
0111 |
13 |
1101 |
1011 |
6 |
0110 |
0101 |
14 |
1110 |
1001 |
7 |
0111 |
0100 |
15 |
1111 |
1000 |
當從7變為8時,4位二進制數都發生跳變,這就很可能會發生亞穩態。而采用格雷碼,就可以編碼4位二進制數都同時發生跳變,導致出現的亞穩態,就算出現亞穩態,最多也就一位出現錯誤。
格雷碼轉二進制
格雷碼轉二進制碼的公式,如下所示:
b[n-1]=g[n-1], b[i]=gray[i]^b[i+1], i=[0,1,...,n-2]
其運算過程的示意圖如圖2所示(這里以8位的數據位寬為例):
格雷碼轉二進制碼示意圖
從圖可以看出,除格雷碼的最高位直接賦給二進制碼的最高位外,其他二進制碼位等對應格雷碼位與其高位格雷碼位異或的結果,因此可歸納出一表達式,如下所示(其中“^”表示變量各位異或):
for(i = 0; i < n-1; i++) b[i] = ^(gray >> i);
觀察上表可知,格雷碼轉二進制是從左邊第二位起,將每位與左邊一位二進制碼的值異或,作為該位二進制碼后的值(最左邊一位依然不變)。
module gray_to_bin( gray_in, bin_out ); parameter data_width = 4;
input [data_width-1:0] gray_in; output [data_width-1:0] bin_out; reg [data_width-1:0] bin_out; always @(gray_in) begin bin_out[3] = gray_in[3]; bin_out[2] = gray_in[2]^bin_out[3]; bin_out[1] = gray_in[1]^bin_out[2]; bin_out[0] = gray_in[0]^bin_out[1]; end endmodule |
二進制轉格雷碼
首先給出二進制碼轉格雷碼的公式,如下所示(以下公式中二進制碼和格雷碼都是n位的):
g[n-1]=b[n-1], g[i]=b[i]^b[i+1], i=[0,1,...,n-2]
其運算過程的示意圖如圖1所示(這里以8位的數據位寬為例):
二進制碼轉格雷碼示意圖
從圖可以很輕易的看出,二進制碼右移1位后與本身異或,其結果就是格雷碼。
從最右邊一位起,依次將每一位與左邊一位異或(XOR),作為對應格雷碼該位的值,最左邊一位不變。
module bin_to_gray( bin_in, gray_out ); parameter data_width = 4;
input [data_width-1:0] bin_in; output [data_width-1:0] gray_out;
assign gray_out = (bin_in >> 1) ^ bin_in;
endmodule |
格雷碼計數器原理
格雷碼計數器,采用三個模塊進行設計,格雷碼轉二進制、加法器、二進制轉格雷碼。
格雷碼轉二進制將格雷碼轉換為二進制,並將值輸出用於加法器進行加法運算,然后將加法運算結果通過二進制轉格雷碼轉換為格雷碼,最后將格雷碼進行輸出,同時將結果輸出到格雷碼轉二進制作為輸入,形成一個計數功能。
頂層設計
module gray_counter( clk, reset_n, // gray_in, gray_out ); parameter data_width = 4;
input clk; input reset_n; // input [data_width-1:0] gray_in; output [data_width-1:0] gray_out;
//格雷碼轉二進制 wire [data_width-1:0] bin_out; gray_to_bin gray_to_bin_1( .gray_in (gray_wire), .bin_out (bin_out) ); //二進制加一 wire [data_width-1:0] bin_add_wire; assign bin_add_wire = bin_out + 1'b1; //二進制轉格雷碼 wire [data_width-1:0] gray_wire; reg [data_width-1:0] gray_out; bin_to_gray bin_to_gray_1( .bin_in (bin_add_wire), .gray_out (gray_wire) );
always @(posedge clk or negedge reset_n) begin if(reset_n == 1'b0) begin gray_out <= {data_width{1'b0}}; end else begin gray_out <= gray_wire; end end endmodule |