目录
格雷码转换电路
1、简介
1.2、格雷码转化为二进制码原理如下:
1.3、二进制码转化为格雷码原理如下:
2、实验任务
3、程序设计
3.1、格雷码转换二进制
3.2、二进制转换格雷码
4、仿真测试
5、仿真验证
格雷码,是一种二进制循环码。格雷码的特点是从一个数变为相邻的一个数时,只有一个数据位发生跳变,由于这种特点,就可以避免二进制编码计数组合电路中出现的亚稳态。格雷码常用于通信,异步 FIFO 或者 RAM 地址寻址计数器中。
格雷码是一个叫弗兰克*格雷的人在 1953 年发明的,最初用于通信。格雷码是一种循环二进制码或者叫作反射二进制码。格雷码的特点是从一个数变为相邻的一个数时,只有一个数据位发生跳变,由于这种特点,就可以避免二进制编码计数组合电路中出现的亚稳态。格雷码常用于通信,FIFO 或者 RAM 地址寻址计数器中。
格雷码属于可靠性编码,是一种错误最小化的编码方式,因为虽然二进制码可以直接由数/模转换器转换成模拟信号,但在某些情况,例如从十进制的 3 转换为 4 时二进制码的每一位都要变,能使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它在相邻位间转换时,只有一位产生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。
二进制计数编码从 0 到 15 的计数过程如下:
从上面的对应关系微妙可以看出,当数字从 7 变为 8 时,4 位二进制数都发生跳变,如果直接使用异步时钟采样这些数字信号,这就很可能会发生亚稳态或者数据采样错误。而采用格雷码,就可以避免 4 位二进制数都同时发生跳变,导致出现的亚稳态,就算出现亚稳态,最多也就一位出现错误。
一般数字设计里面都是使用二进制码,那么我们想使用格雷码需要怎么转换呢?这就涉及到格雷码和二进制码互相转换的问题。我们先来看下格雷码如何转换到二进制码。
使用格雷码的最高位作为二进制的最高位,二进制次高位产生过程是使用二进制的高位和次高位格雷码相异或得到,其他位的值与次高位产生过程类似。假设二进制和格雷码各个位分别使用如下字符表示:
其运算过程的示意图如下图所示(这里以 8 位的数据位宽为例):
下面我们演示一个 4bit 的格雷码和二进制转换的例子。
从图中可以看出,二进制最高位和格雷码最高位相同,都是 1,次高位为二进制的高位和次高位格雷码相异或得到,即 bit2 为 0=1^1。
介绍完格雷码如何转换到二进制后,我们再来看下二进制码如何转换到格雷码。
二进制的最高位作为格雷码的最高位,次高位的格雷码为二进制的高位和次高位相异或得到,其他位与次高位类似。假设二进制和格雷码各个位分别使用如下字符表示:
其运算过程的示意图如下图所示(这里以 8 位的数据位宽为例):
从图可以很容易的看出,二进制码右移 1 位后与本身异或,其结果就是格雷码。从最右边一位起,依次将每一位与左边一位异或(XOR),作为对应格雷码该位的值,最左边一位不变。
使用 Verilog 语言设计格雷码转换二进制电路和二进制转换格雷码电路。
我们先来编写格雷码转换二进制的代码,根据简介介绍的格雷码转换二进制的思路,我们可以写出如下代码。
代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/20 17:15:34
// Design Name:
// Module Name: gray_to_bin
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//实验任务
//使用 Verilog 语言设计格雷码转换二进制电路和二进制转换格雷码电路。
//格雷码转换二进制
module gray_to_bin(
gray_in,
bin_out
);
//parameter define
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
我们再先来编写二进制转换格雷码的代码,根据简介介绍的二进制转换格雷码的思路,我们可以写出如下代码。
代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/20 17:17:23
// Design Name:
// Module Name: bin_to_gray
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//实验任务
//使用 Verilog 语言设计格雷码转换二进制电路和二进制转换格雷码电路。
//二进制转换格雷码
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
下面我们编写一个 testbech 测试电路,这个 testbech 激励需要一个连续变化的二进制数,输入 a 信号持续 100ns 累加一次,我们通过仿真来看下二进制转换格雷码的波形。
测试代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/20 17:23:23
// Design Name:
// Module Name: tb_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_test();
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
测试程序在 Modelsim 或者其他仿真工具(Xilinx 的 Vivado 软件也有仿真功能)运行后的波形如下显示,可以看出,当二进制数字依次累加的时候,都是有几个 bit 发生跳变,而格雷码每次变化都是只有 1 个bit 发生跳变,注意,这种情况只适用于二进制依次累加的时候,如果二进制变化没有任何规律,那么格雷码也可能发生多 bit 的跳变,而 FIFO 设计中的读写地址都是连续变化的,因此格雷码适用于 FIFO 的地址处理。