1、什么是格雷码
格雷码是一种循环二进制码或者叫作反射二进制码。格雷码的特点是从一个数变为相邻的一个数时,只有一个数据位发生跳变,由于这种特点,就可以避免二进制编码计数组合电路中出现的亚稳态。格雷码常用于通信,FIFO 或者 RAM 地址寻址计数器中。
下表给出了4bit自然二进制码、4bit典型格雷码(无特殊说明,典型格雷码即格雷码)与4bit十进制整数的对照:
可以看到,上表中格雷码的每次变化位数只有一位,这就有效的避免了在CDC情况(跨时钟域情况)下亚稳态问题发生的概率。比如当数字从 7 变为 8 时,4 位二进制数都发生跳变,如果直接使用异步时钟采样这些数字信号,这就很可能会发生亚稳态或者数据采样错误。而采用格雷码,就可以避免 4 位二进 制数都同时发生跳变,导致出现的亚稳态,就算出现亚稳态,最多也就一位出现错误。
但是由于格雷码是一种变权码,每一位码没有固定的大小,所以很难直接进行比较大小和算术运算。
2、二进制转格雷码
二进制码转化为格雷码原理如下:
二进制的最高位作为格雷码的最高位,次高位的格雷码为二进制的高位和次高位相异或得到,其他位与次高位类似。转化过程如下图:
假如是4bit的二进制数据转成格雷码则是:
- gray[3] = 0 ^ bin[3];----gray[3] = bin[3] 异或0等于自身
- gray[2] = bin[3] ^ bin[2];
- gray[1] = bin[2] ^ bin[1];
- gray[0] = bin[1] ^ bin[0];
根据上面的式子不难推到出一般公式:gray = (bin >> 1) ^ bin。根据公式很容易写出二进制码转换为格雷码的Verilog代码:
1
2
3
4
5
6
7
8
9
10
11
12
13//二进制转格雷码 module bin2gray #( parameter data_width = 'd4 //数据位宽 ) ( input [data_width - 1 : 0] bin , //二进制 output [data_width - 1 : 0] gray //格雷码 ); assign gray = (bin >> 1) ^ bin; endmodule
3、格雷码转二进制
格雷码转化为二进制码原理如下:
使用格雷码的最高位作为二进制的最高位,二进制次高位产生过程是使用二进制的高位和次高位格雷码相异或得到,其他位的值与次高位产生过程类似。转化过程如下图:
假如是4bit的格雷码转成二进制则是:
- bin[3] = gray[3] ;
- bin[2] = gray[2] ^ bin[3];
- bin[1] = gray[1] ^ bin[2];
- bin[0] = gray[0] ^ bin[1];
可以看到,最高位不需要转换,从次高位开始使用二进制的高位和次高位格雷码相异或,那么可以使用generate--for来构建重复赋值语,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//格雷码转二进制 module gray2bin #( parameter data_width = 'd4 //数据位宽 ) ( input [data_width - 1 : 0] gray, //格雷码 output [data_width - 1 : 0] bin //二进制 ); assign bin[data_width - 1] = gray[data_width - 1]; //最高位直接相等 //从次高位到0,二进制的高位和次高位格雷码相异或 genvar i; generate for(i = 0; i <= data_width-2; i = i + 1) begin: gray //需要有名字 assign bin[i] = bin[i + 1] ^ gray[i]; end endgenerate endmodule
4、测试
构建一个测试脚本对两个模块进行测试:生成0-15的4bit二进制数据,通过bin2gray转换成格雷码,观察格雷码输出;将转换后的格雷码输出通过gray2bin再转换成2进制码,然后对比三组数据是否符合转换规则。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38`timescale 1ns/1ns //时间单位/精度 //------------<模块及端口声明>---------------------------------------- module gray_code(); parameter data_width = 'd4; //数据位宽 reg [data_width - 1 : 0] bin_in; //生成的二进制码 wire [data_width - 1 : 0] gray; //转换后的格雷码 wire [data_width - 1 : 0] bin_out; //转换后的二进制码 //------------<例化被测试模块>---------------------------------------- bin2gray #( .data_width (data_width) ) bin2gray_inst( .bin (bin_in ), .gray (gray ) ); gray2bin #( .data_width (data_width) ) gray2bin_inst( .bin (bin_out ), .gray (gray ) ); //------------<设置初始测试条件>---------------------------------------- initial begin bin_in = 4'd0; forever #20 bin_in = bin_in + 1; //每隔20ns累加1 end //打印输出 initial $monitor("bin_in:%b, gray:%b, bin_out:%b",bin_in,gray,bin_out); endmodule
仿真结果如下:
可以看到两次转换的结果都是正确的,接下来看一下命令窗口打印的输出:
可以看到这个转换结果与第一章的对照表是一致的。
最后
以上就是拼搏花卷最近收集整理的关于Verilog实现的格雷码与二进制码的互相转换1、什么是格雷码2、二进制转格雷码3、格雷码转二进制4、测试的全部内容,更多相关Verilog实现内容请搜索靠谱客的其他文章。
发表评论 取消回复