跳转至

实验六 计数器实验

实验目的

  1. 掌握时序逻辑电路的基本分析和设计方法;
  2. 掌握计数器电路设计原理,用硬件描述语言实现指定功能的计数器设计。

实验内容

用硬件描述语言实现 0 ~ 59 的计数器,然后下载到 FPGA 中进行验证。

设计需求

  1. 设计 00 ~ 59 的计数器,手动输入时钟,时钟上升沿计数一次,当计数到 59 后,计数回到 00,重新开始计数,复位按键下降沿可以随时复位到 00 的状态。
  2. 使用时钟模块上的复位开关 CLK 作为手动时钟输入,复位开关 RST 作为复位输入。
  3. 使用不带译码的七段数码管模块的两个七段数码管分别作为计数器高低两位的输出 High[6:0]Low[6:0]

设计框图

flowchart LR

  CLK[复位开关CLK]:::periph -- CLK ---> counter;

  RST[复位开关RST]:::periph -- RST ---> counter;

  subgraph FPGA
    direction BT
    counter[计数器Counter]:::seq;

    counter -- cnt_H --> decoderH[译码器]:::comb;
    counter -- cnt_L --> decoderL[译码器]:::comb;
  end

  decoderH -- High --> seg1[七段数码管]:::periph;

  decoderL -- Low --> seg2[七段数码管]:::periph;

  classDef comb fill:#e8f5e9,stroke:#43a047;   %% green
  classDef seq fill:#ffecb3,stroke:#ffa000;    %% orange
  classDef periph fill:#e3f2fd,stroke:#2196f3; %% blue
  linkStyle default opacity:1.0

原理图

00 ~ 59 计数器

计数器的功能是将根据 CLK 输入,在其上升沿的时候计数加一,计数范围在 00 ~ 59;当复位输入 RST 下降沿的时候计数清零。

因此计数器内部需要有两个计数部分,分别负责高位计数 cnt_H 和低位计数 cnt_L,低位计数 cnt_L 到 9 后回到 0 并且高位计 cnt_H 数加一,高位计数 cnt_H 到 5 后回到 0。

高位计数 cnt_H 和低位计数 cnt_L 都是 BCD 码,需要通过译码器输出到七段数码管上,让数码管显示正确的数字,因此需要在计数器内部例化两个数码管的译码器。

下面给出的代码仅供参考

module Counter (
    input wire CLK, 
    input wire RST, 
    output reg [6:0] High, 
    output reg [6:0] Low 
    );

    reg [3:0] cnt_H;
    reg [3:0] cnt_L;

    always_ff @(posedge CLK or negedge RST) begin
        if(!RST) begin
            cnt_H <= 0;
            cnt_L <= 0;
        end else begin
            if (cnt_L == 9) begin
                if(cnt_H == 5) begin
                    cnt_H <= 0;
                    cnt_L <= 0;
                end else begin
                    cnt_H <= cnt_H + 1;
                    cnt_L <= 0;
                end
            end else begin
                cnt_L <= cnt_L + 1;
            end
        end
    end

    Decoder u1 (
        .d (cnt_H),
        .seg (High)
    );

    Decoder u2 (
        .d (cnt_L),
        .seg (Low)
    );
endmodule

同步/异步复位

这里采用的是异步复位,当复位信号RST出现下降沿的时候进行复位;也可以采用同步复位的方式,当时钟CLK信号上升沿的时候如果复位信号RST为低的时候进行复位,这样就不用考虑RST的下降沿了。

管脚绑定

使用可编程模块上的接插孔连接复位开关和七段数码管,其中 CLK 作为时钟输入 CLK,IO0 作为复位输入 RST,IO1 ~ IO7 作为高位七段数码管输出 High[6:0],IO11 ~ IO17 作为低位七段数码管输出 Low[6:0], 具体约束文件如下:

#CLK input
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports CLK];     #CLK接插孔

#RST input
set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports RST];     #IO0接插孔

# High output
set_property -dict {PACKAGE_PIN M21 IOSTANDARD LVCMOS33} [get_ports High[6]];     #IO1接插孔
set_property -dict {PACKAGE_PIN N20 IOSTANDARD LVCMOS33} [get_ports High[5]];     #IO2接插孔
set_property -dict {PACKAGE_PIN N22 IOSTANDARD LVCMOS33} [get_ports High[4]];     #IO3接插孔
set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports High[3]];     #IO4接插孔
set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports High[2]];     #IO5接插孔
set_property -dict {PACKAGE_PIN T21 IOSTANDARD LVCMOS33} [get_ports High[1]];     #IO6接插孔
set_property -dict {PACKAGE_PIN U21 IOSTANDARD LVCMOS33} [get_ports High[0]];     #IO7接插孔

# High output
set_property -dict {PACKAGE_PIN W21 IOSTANDARD LVCMOS33} [get_ports Low[6]];     #IO11接插孔
set_property -dict {PACKAGE_PIN W22 IOSTANDARD LVCMOS33} [get_ports Low[5]];     #IO12接插孔
set_property -dict {PACKAGE_PIN Y22 IOSTANDARD LVCMOS33} [get_ports Low[4]];     #IO13接插孔
set_property -dict {PACKAGE_PIN Y21 IOSTANDARD LVCMOS33} [get_ports Low[3]];     #IO14接插孔
set_property -dict {PACKAGE_PIN AB22 IOSTANDARD LVCMOS33} [get_ports Low[2]];     #IO15接插孔
set_property -dict {PACKAGE_PIN AA18 IOSTANDARD LVCMOS33} [get_ports Low[1]];     #IO16接插孔
set_property -dict {PACKAGE_PIN AB18 IOSTANDARD LVCMOS33} [get_ports Low[0]];     #IO17接插孔

# required if touch button used as manual clock source
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets CLK_IBUF]

set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]

关于约束和引脚绑定

此处出现了之前实验未出现的约束语句:

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets CLK_IBUF]

它用于特定场景中对时钟网络的路由进行配置,下面是这个命令的各部分的解释:

set_property 是一个设置属性的命令,用于修改或指定设计中某些元素的特性。

CLOCK_DEDICATED_ROUTE 是一个特定属性,用来指定时钟信号的路由方式。

FALSE 表示不使用专用的时钟路由。通常,时钟信号为了保持低延迟和高性能,会通过FPGA内部的专用时钟网络进行路由。将此属性设置为 FALSE 可能是因为设计中的某些限制或特殊需求,需要通过非专用的路径来路由时钟信号,这可能会增加时钟信号的延迟和抖动。

[get_nets CLK_IBUF] 指定这个属性应用于哪个网络。在这里,CLK_IBUF 通常是指一个输入缓冲器(IBUF)的输出,该输出承载着来自FPGA外部的时钟信号。

实验步骤

  1. 使用 vivado2019.2 新建一个工程,编写 system verilog 代码,并进行综合;
  2. 进行功能仿真;
  3. 使用时钟模块,不带译码的数码管模块和可编程模块,进行电路连接;
  4. 管脚绑定,编译并下载,观察实验结果。

提高要求

  1. 使用时钟模块上的 1M 时钟,将计数器改成秒表;
  2. 使用开关模块上的拨动开关控制秒表启动/暂停。

实验报告

  1. 整理出完整、清晰的代码,并详细添加注释说明电路的工作原理。
  2. 给出软件仿真的结果。
  3. 说明电路功能测试的结果,并与软件仿真的结果相比较。
  4. 总结调试中所遇到的问题及解决方法。

最后更新: 2024年5月30日
作者:cuibst (0.57%), 李山山 (86.86%), Jiajie Chen (3.43%), liuh22 (9.14%)