Verilog——格雷码计数器

- 格雷码(Gray code):
第一次接触格雷码是在本科的数电课本上,其在可靠性编码占据重要位置。后来所学的卡诺图与格雷码关系密切。
格雷码特点在于相邻性和单位距离性。在代码传输过程中,彼此相邻位置仅有一位数码不同,故有着较好的可靠性。
4位格雷码:

十进制 二进制 格雷码
0 0000 0000
1 0001 0001
2 0010 0011
3 0011 0010
4 0100 0110
5 0101 0111
6 0110 0101
7 0111 0100
8 1000 1100
9 1001 1101
10 1010 1111
11 1011 1110
12 1100 1010
13 1101 1011
14 1110 1001
15 1111 1000

- Verilog的实现:
格雷码计数器的Verilog实现,即用格雷码计数的方式,完成数据的累加。
实现方式有多种,参考J.Bhasker的书,此处贴上第一种。
代码的基本流程为:首先将初始化的格雷码转变为二级制码,二进制完成累加,最后再讲二级制码转化为格雷码。

  1. 格雷码转二进制码的基本思路:
    最高位不变,次高位往下依次完成自异或运算,得到对应二进制码的各位数据,运算次数为位宽-1
  2. 二进制码转格雷码的基本思路:
    最高位不变,最低位依次往前完成自异或运算,得到对应二进制码的各位数据,运算次数为位宽-1
  3. 注:这样的自异或运算与其他人给出的格雷码+二进制共同运算的方式不同,前一种可能存在局限性,待发现后说明

异步复位的N位格雷码计数器

`timescale 1ns/1ns
module gray_counter1(ck,preclear,q);

parameter NBITS = 4;    //决定格雷码计数的带宽
input ck,preclear;
output [0:NBITS-1] q;

reg [0:NBITS-1] q;
reg [0:NBITS-1] gray_cnt;
integer k;

always @(posedge ck or negedge preclear)
begin
    if(!preclear)   //异步清零信号,信号为低时,计数清零
        q <= 0;
    else 
    begin
        gray_cnt = q;
        //将数据存在在临时变量中

    for(k=1;k<NBITS;k=k+1)
        if(gray_cnt[k-1])
            gray_cnt[k] = !gray_cnt[k];//高位为高,低位取反,本质上是异或操作
        //完成格雷码到二进制的转换,二进制计数

    gray_cnt = gray_cnt + 1;

    for(k=NBITS-1;k>0;k=k-1)
        if(gray_cnt[k-1])
            gray_cnt[k] = !gray_cnt[k];
        //二进制转回格雷码

    q <= gray_cnt;
    end
end
endmodule       

module gray_counter1_tb;    //测试文件
parameter NBITS = 4;

reg ck,preclear;
wire [0:NBITS-1] q;

gray_counter1 U1(ck,preclear,q);

always #50 ck = !ck;    //计数时钟,周期100ns

initial 
begin
    ck = 0;
    preclear = 1;
    #70 preclear = 0;
    #70 preclear = 1;
end

endmodule

猜你喜欢

转载自blog.csdn.net/u013668469/article/details/81587944