前言:本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载

示例:计数器

 

  • 功能特性: 采用 Xilinx Artix-7 XC7A35T芯片 
  • 配置方式:USB-JTAG/SPI Flash
  • 高达100MHz 的内部时钟速度 
  • 存储器:2Mbit SRAM   N25Q064A SPI Flash(样图旧款为N25Q032A)
  • 通用IO:Switch :x8LED:x16Button:x5DIP:x8   通用扩展IO:32pin
  • 音视频/显示: 7段数码管:x8 VGA视频输出接口 Audio音频接口 
  • 通信接口:UART:USB转UART   Bluetooth:蓝牙模块 
  • 模拟接口: DAC:8-bit分辨率   XADC:2路12bit 1Msps ADC

目录

Ⅰ. 前置知识

0x00 利用D触发器构造环形计数器(自循环移位寄存器)

0x01  扭环形计数器(约翰逊计数器)

 Ⅱ. Verilog实现:

0x00 环形计数器

0x01 扭环计数器


Ⅰ. 前置知识

0x00 利用D触发器构造环形计数器(自循环移位寄存器)

下图为利用D触发器构造的计数器电路,如果初始时将A、B、C、D置为1000,CP接单脉冲计数,则计数器可以实现one-hot计数。

环形计数器原理

参考程序如下,

module circle_counter(rst_n, clk, cnt ); 
parameter CNT_SIZE = 8;
input rst_n;
input clk;
output [CNT_SIZE-1 : 0] cnt;
reg [CNT_SIZE-1 : 0] cnt;
always@(posedge clk)
    if(!rst_n)
        cnt <= 8'b0000_0001;  //初始值
    else
        cnt <= {cnt[0],cnt[CNT_SIZE-1 : 1]};//注意是循环移位,而非简单的移位
        //cnt <= cnt>>1;
Endmodule

在下图中,用74LS10的三输入端与非门修改上述电路,使得初始值0000启动时,下一个CP脉冲时计数器状态可以自行跳至1000。

请自行总结自启动的体会。(注意:74LS10有一个门起非门作用)

  自启式环形计数器

参考程序如下:

module circle_counter(rst_n, clk, cnt ); 
parameter CNT_SIZE = 8;
input rst_n;
input clk;
output [CNT_SIZE-1 : 0] cnt;
reg [CNT_SIZE-1 : 0] cnt;
always@(posedge clk)
    if(!rst_n)
        cnt <= 8'b0000_0001;  //初始值
    else
        cnt <= {cnt[0],cnt[CNT_SIZE-1 : 1]};//注意是循环移位,而非简单的移位
        //cnt <= cnt>>1;
Endmodule

上面的代码仅仅是简单的实现,模拟环形计数器的工作方式,并没有过多的考虑自启动的问题。

对于环形计数器,功能上又被称作one-hot(独热码)计数器,优点是速度快,且每次只有两个bit发生跳变,而且不需外加译码电路,可以直接以各个触发器输出端的1状态表示计数。

主要缺点是没有有效利用电路的状态,对于n bit,有2n-n个状态没有利用。应用中,在状态机的状态编码时,经常用到此类计数器,如4bit one-hot计数器的计数序列即为:0001-0010-0100-1000循环。也因此,大多情况下这种计数器不被称作计数器,而是状态编码的一种。

若要设计可以自启动(自动从无效状态转移到有效状态,进入有效循环)的电路,可参考附加实验中状态机设计的实验内容,通过修改状态逻辑实现,本质是改变无效状态的次态,使其为有效状态。

0x01  扭环形计数器(约翰逊计数器)

基本原理:设置一个初始状态,将最高位取反,作为最低位的输入,通过移位即可得到。

如图:

  扭环形计数器原理示意

参考代码:

module john_counter(rst_n, clk, cnt );
parameter CNT_SIZE = 4;
input rst_n;
input clk;
output [CNT_SIZE-1 : 0] cnt;
reg [CNT_SIZE-1 : 0] cnt;
always@(posedge clk)
    if(!rst_n)
        cnt <= 4'b0000 ;  //初始值
    else
        cnt <= {~cnt[0],cnt[CNT_SIZE-1 : 1]}; //注意是循环移位,而非简单的移位
endmodule

 Ⅱ. Verilog实现:

0x00 环形计数器

设计代码:

module circle_counter(rst_n, clk, cnt ); 
parameter CNT_SIZE = 8;
input rst_n;
input clk;
output [CNT_SIZE-1 : 0] cnt;
reg [CNT_SIZE-1 : 0] cnt;
always@(posedge clk)
 if(!rst_n)
 cnt <= 8'b0000_0001; 
 else
 cnt <= {cnt[0],cnt[CNT_SIZE-1 : 1]};
endmodule

仿真代码:

module test();
reg rst_n,clk;
wire [7:0]cnt;
circle_counter uut(.rst_n(rst_n),. clk(clk),. cnt(cnt));
initial begin 
		clk = 'b0;
		rst_n = 'b0;
		# 10
		rst_n = 'b1;
        # 2000
                $finish;
            end
        
            always #5 clk = ~clk;
endmodule


仿真波形图:

0x01 扭环计数器

 设计文件:

module john_counter(rst_n, clk, cnt );
parameter CNT_SIZE = 4;
input rst_n;
input clk;
output [CNT_SIZE-1 : 0] cnt;
reg [CNT_SIZE-1 : 0] cnt;
always@(posedge clk)
 if(!rst_n)
 cnt <= 4'b0000 ; 
 else
 cnt <= {~cnt[0],cnt[CNT_SIZE-1 : 1]}; 
 endmodule

仿真文件:

module john_counter(rst_n, clk, cnt );
parameter CNT_SIZE = 4;
input rst_n;
input clk;
output [CNT_SIZE-1 : 0] cnt;
reg [CNT_SIZE-1 : 0] cnt;
always@(posedge clk)
 if(!rst_n)
 cnt <= 4'b0000 ; 
 else
 cnt <= {~cnt[0],cnt[CNT_SIZE-1 : 1]}; 
 endmodule

仿真波形图: