(1)深入了解计数器原理
(2)学习使用Verilog实现同步计数器(模八)
计数器的功能是记忆脉冲个数,它是数字系统中应用最为广泛的时序逻辑构件。
下图为设计
计数器从0开始每隔25_000_000个时钟周期(0.25秒)数码管末位显示加一,最大值为7,7后复0值
module Counter8(
input wire Clk,//时钟信号E3
input wire rst_n,//复位信号 置零
output reg [3:0] oQ,
output reg [6:0] oDisplay,//控制数码管亮段
output reg [7:0] an//控制数码管位数
// input wire count
);
parameter COUNT = 25'd24_999_999;//每隔0.25秒计数器加一
reg[24:0] cnt;//计数
initial begin
oQ[3:0] = 4'b0000;
cnt=25'b0;
an[7:0]=8'b11111110;//控制最后一位数码管亮,其他位数码管不亮
end
always@(posedge Clk)begin
if(Clk==1'b0)
cnt<=1'b0;
else if(cnt==COUNT)//当第8隔0.25秒后计数器重新记数
cnt<=25'b0;
else
cnt<=cnt+1'b1;
end
always@(posedge Clk) begin
if(rst_n)
oQ<=4'b0000;
else
if(oQ == 4'b1000)
oQ<=4'b0000;
else if(cnt==COUNT)//判断计数器是否加一
oQ<=oQ+1'b1;
end
always@(*)
case(oQ)
4'b0000:oDisplay[6:0]=7'b1000000;//数码管显示0
4'b0001:oDisplay[6:0]=7'b1111001;//数码管显示1
4'b0010:oDisplay[6:0]=7'b0100100;//数码管显示2
4'b0011:oDisplay[6:0]=7'b0110000;//数码管显示3
4'b0100:oDisplay[6:0]=7'b0011001;//数码管显示4
4'b0101:oDisplay[6:0]=7'b0010010;//数码管显示5
4'b0110:oDisplay[6:0]=7'b0000010;//数码管显示6
4'b0111:oDisplay[6:0]=7'b1111000;//数码管显示7
default:
oDisplay[6:0]=7'b1111111;//其他情况不亮
endcase
endmodule
这是一个 Verilog 模块,它实现了一个从 0 到 8 的数字计数器,并将计数显示在七段数码管上。计数器每隔 0.25 秒就会自动增加 1,这一点由参数 COUNT
确定。
输入 Clk
是时钟信号,输入 rst_n
是复位信号。当 rst_n
为低电平时,计数器会被重置为 0。输出 oQ
是一个 4 位的向量,保存当前计数值。输出 oDisplay
是一个 7 位的向量,控制七段数码管的各个段来显示计数值。输出 an
是一个 8 位的向量,控制哪个七段数码管的数字位应该被打开。
在这个模块中有两个 always
块。第一个块在时钟信号 Clk
上升沿触发,更新计数器 cnt
的值。如果计数器已经到达最大值 COUNT
,它就会被重置为 0。否则,它就会增加 1。第二个 always
块也在时钟信号 Clk
上升沿触发,更新输出 oQ
的值。如果复位信号 rst_n
为高电平,输出就会被重置为 0。否则,如果输出 oQ
已经到达最大值 9,它就会被重置为 0。否则,如果计数器 cnt
已经到达最大值 COUNT
,输出 oQ
就会增加 1。
还有一个 case
语句,根据输出 oQ
的值为输出 oDisplay
赋值。每个 oQ
的值对应着七段数码管上特定的一组亮段模式,用于显示一个特定的数字。如果 oQ
有任何其他值,所有的段都会被关闭。
module test();
reg Clk;
reg rst_n;
reg count;
wire [2:0] oQ;
wire [6:0] oDisplay;
Counter8 counter(.Clk(Clk),
.oDisplay(oDisplay),
.rst_n(rst_n),
.oQ(oQ),
.count(count)
);
initial begin
Clk=0;
rst_n=0;
count = 0;
end
always #10 Clk=~Clk;
always #10 count=~count;
endmodule
这是一个 Counter8
模块的测试台。它创建了一个时钟信号 Clk
和一个复位信号 rst_n
,并用 count
的值驱动 Counter8
模块的 count
输入。它还将 Counter8
模块的输出 oQ
和 oDisplay
连接到测试台上。
initial
块将 Clk
、rst_n
和 count
的初始值都设置为 0。两个 always
块通过每隔 10 个时间单位就交替改变 Clk
的值来创建时钟信号,并且每隔 10 个时间单位就切换 count
的值。
你可以通过运行模拟并观察模拟过程中输出 oQ
和 oDisplay
的值来使用这个测试台来测试 Counter8
模块的行为。
set_property PACKAGE_PIN L18 [get_ports {oDisplay[6]}]
set_property PACKAGE_PIN T11 [get_ports {oDisplay[5]}]
set_property PACKAGE_PIN P15 [get_ports {oDisplay[4]}]
set_property PACKAGE_PIN K13 [get_ports {oDisplay[3]}]
set_property PACKAGE_PIN K16 [get_ports {oDisplay[2]}]
set_property PACKAGE_PIN R10 [get_ports {oDisplay[1]}]
set_property PACKAGE_PIN T10 [get_ports {oDisplay[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oDisplay[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oQ[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oQ[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {oQ[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports Clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property PACKAGE_PIN E3 [get_ports Clk]
set_property PACKAGE_PIN M18 [get_ports rst_n]
set_property PACKAGE_PIN H17 [get_ports {oQ[0]}]
set_property PACKAGE_PIN K15 [get_ports {oQ[1]}]
set_property PACKAGE_PIN J13 [get_ports {oQ[2]}]
这是一系列 Xilinx 工具链中的命令,它们将 FPGA 的物理封装引脚分配给 Counter8
模块的输入和输出端口。前七个命令分别将 Counter8
模块的输出 oDisplay
分配给封装引脚 L18、T11、P15、K13、K16、R10 和 T10。接下来的七个命令将这些引脚的 I/O 标准设置为 LVCMOS33。最后的五个命令分别将 Counter8
模块的输入 Clk
和 rst_n
,以及输出 oQ
分配给封装引脚 E3、M18、H17、K15 和 J13,并将这些引脚的 I/O 标准设置为 LVCMOS33。
演示视频
https://www.bilibili.com/video/BV1144y1D7GZ/?vd_source=e40d8b41352b267106c91fbabf8bba0e
复位调零