二进制与格雷码互相转换

以下内容摘自:《正点原子逻辑设计指南》

格雷码,是一种二进制循环码。格雷码的特点是从一个数变为相邻的一个数时,只有一个数据位发生跳变,由于这种特点,就可以避免二进制编码计数组合电路中出现的亚稳态。格雷码常用于通信,异步 FIFO或者 RAM 地址寻址计数器中。

一、格雷码简介

格雷码是一个叫弗兰克*格雷的人在 1953 年发明的,最初用于通信。格雷码是一种循环二进制码或者叫作反射二进制码。格雷码的特点是从一个数变为相邻的一个数时,只有一个数据位发生跳变,由于这种特点,就可以避免二进制编码计数组合电路中出现的亚稳态。格雷码常用于通信,FIFO 或者 RAM 地址寻址计数器中。

格雷码属于可靠性编码,是一种错误最小化的编码方式,因为虽然二进制码可以直接由数/模转换器转换成模拟信号,但在某些情况,例如从十进制的 3 转换为 4 时二进制码的每一位都要变,能使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它在相邻位间转换时,只有一位产生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。

二进制计数编码从 0 到 15 的计数过程如下:
在这里插入图片描述
从上面的对应关系可以看出,当数字从 7 变为 8 时,4 位二进制数都发生跳变,如果直接使用异步时钟采样这些数字信号,这就很可能会发生亚稳态或者数据采样错误。而采用格雷码,就可以避免 4 位二进制数都同时发生跳变,就算出现亚稳态,最多也就一位出现错误。

二、互相转换原理

一般数字设计里面都是使用二进制码,那么我们想使用格雷码需要怎么转换呢?这就涉及到格雷码和二进制码互相转换的问题。我们先来看下格雷码如何转换到二进制码。

格雷码转化为二进制码原理如下:

使用格雷码的最高位作为二进制的最高位,二进制次高位产生过程是使用二进制的高位和次高位格雷码相异或得到,其他位的值与次高位产生过程类似。假设二进制和格雷码各个位分别使用如下字符表示:

n 位的二进制:Bn, Bn-1, Bn-2。。。B2, B1 , B0;
n 位的格雷码:Gn, Gn-1, Gn-2。。。G2, G1, G0;

转换公式:

Bn =Gn;
Bi-1 = Bi ^ Gi-1;( i=1,2,n-1; )

其运算过程的示意图如下图所示(这里以 4 位的数据位宽为例):

在这里插入图片描述
从图中可以看出,二进制最高位和格雷码最高位相同,都是 1,次高位为二进制的高位和次高位格雷码相异或得到,即 bit2 为 0=1^1。


介绍完格雷码如何转换到二进制后,我们再来看下二进制码如何转换到格雷码。

二进制码转化为格雷码原理如下:

二进制的最高位作为格雷码的最高位,次高位的格雷码为二进制的高位和次高位相异或得到,其他位与次高位类似。假设二进制和格雷码各个位分别使用如下字符表示:

n 位的二进制:Bn, Bn-1,Bn-2。。。B2,B1,B0;
n 位的格雷码:Gn, Gn-1,Gn-2。。。G2,G1,G0;

转换公式:
Gn = Bn;
Gi-1=Bi ^ Bi-1; ( i=1,2,n-1; )

其运算过程的示意图如下图所示(这里以 8 位的数据位宽为例):

在这里插入图片描述
从图可以很容易的看出,二进制码右移 1 位后与本身异或,其结果就是格雷码。从最右边一位起,依次将每一位与左边一位异或(XOR),作为对应格雷码该位的值,最左边一位不变。

三、程序设计

格雷码转换二进制的代码:

module gray_to_bin( 
    gray_in, 
    bin_out
);

    parameter WIDTH = 4; 
    input [WIDTH-1:0] gray_in;  
    output reg [WIDTH-1:0] bin_out;
 
 //===================================================
 // ------------------- MAIN CODE -------------------
 //===================================================
 
 always @(*) 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

二进制转换格雷码的代码:

module bin_to_gray( 
      bin_in, 
      gray_out
);

    parameter WIDTH = 4; 

    input [WIDTH-1:0] bin_in; 
    output wire [WIDTH-1:0] gray_out;
 
 //================================================================
 // ------------------------- MAIN CODE --------------------------
 //================================================================
 
    assign gray_out = (bin_in >> 1) ^ bin_in;
    // gray_out[0] = (bin_in[1]) ^ bin_in[0];
    // gray_out[1] = (bin_in[2]) ^ bin_in[1];
    // gray_out[2] = (bin_in[3]) ^ bin_in[2];
    // gray_out[3] = (bin_in[3]) ^ 0 ;
 
 endmodule

四、设计测试

下面我们编写一个 testbench 测试电路,这个 testbench 激励需要一个连续变化的二进制数,输入 a 信号持续 100ns 累加一次,我们通过仿真来看下二进制转换格雷码的波形。

module TB();
 
    reg [3:0] a ; 
    wire [3:0] y ;

    initial begin
        a = 4'd0;
        #100
        a = 4'd1;
        #100
        a = 4'd2;
        #100
        a = 4'd3;
        #100
        a = 4'd4;
        #100
        a = 4'd5;
        #100
        a = 4'd6;
        #100
        a = 4'd7;
        #100
        a = 4'd8;
        #100
        a = 4'd9;
        #100
        a = 4'd10;
        #100
        a = 4'd11;
        #100
        a = 4'd12;
        #100
        a = 4'd13;
        #100
        a = 4'd14;
        #100
        a = 4'd15; 
 
    end
 
    bin_to_gray u_bin_to_gray (
        .bin_in (a ),
        .gray_out (y )
    );
 
 endmodule

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39507748/article/details/114643478