一、设计定义
- 有一个LED,每500ms,状态翻转一次,LED亮灭一次,周期为1s。
- 由于FPGA中所使用的时钟是50MHz或100MHz,若想得到500ms,就需要对系统时钟进行计数。
- 系统时钟为50MHz,对应周期为20ns。
- 计数的次数:N=500ms/20ns=500_000_000ns/20ns=25_000_000次。
- 位宽计算:由于
,且
,所以位宽应该为5+20=25。
二、程序编写
- counter.v程序
module counter(Clk50M,Rst_n,led)
input Clk50M; //系统时钟,50MHz
input Rst_n; //全局复位,低电平复位
output led; //led输出
reg [24:0] cnt; //定义计数器寄存器
//计数器计数进程
always@(posedge Clk50M or negedge Rst_n)
if(Rst_n==1'b0) //当按键按下时为低电平,复位状态
cnt<=25'd0;
else if (cnt==25'd24_999_999)
cnt<=25'd0;
else
cnt<=cnt+1'b1;
//LED输出控制进程
always@(posedge Clk50M or negedge Rst_n)
if(Rst_n==1'b0)
led<=1'b1; //复位状态时,高电平,LED灭
else if (cnt=25'd24_999_999) //计满500ms后,led翻转一次
led=~led;
else
led<=led;
endmodule
- testbench下的counter_tb.v程序
`timescale 1ns/1ns //定义仿真步径和仿真精度
`define clock_period 20
module counter_tb;
input clk;
input rst_n;
wire led;
counter counter0(
.Clk50M(clk),
.Rst_n(rst_n),
.led(led)
);
initial clk=1;//仿真开始时,clk为高电平
always #(`clock_period/2) clk=~clk; //#后加时间,表示延时,延时10ns翻转一次
initial begin //产生复位信号
rst_n=1'b0;
#(`clock_period*200); //延时200个周期后,信号被释放
rst_n=1'b1;
#2000000000; //一次完整的翻转需要1s,如果小于1s,则将看不到完整的现象,因此应该大于1s,这里选择2s
$stop;
end
endmodule
三、仿真结果分析
1、RTL仿真结果:
从图中可以看出,led的翻转半个周期为500ms,一个周期为1000ms,即1s。
2、门电路仿真(Gate Level Simulation):
由于counter.v程序中cnt==25'd24_999_999太大了,门电路仿真中太慢,因此,在这里将其改为cnt==25'd24_999,若改为24_999,说明led的半个周期为0.5ms,1ms时翻转一次,从仿真波形中可以看出,这几个误差在0.1ns左右,这主要是由于门仿真中从高电平到低电平和从低电平到高电平时间不同导致的,这也可以看出RTL仿真和门仿真是有一定差别的。
3、查看RTL图
点击RTL图可以得到,Quartus生成的RTL图,步骤如下:点击左下角编译过的Analysis&Synthesis---Netlist Viewers--RTL Viewer双击即可得到。从图中看到,里面均有十六进制显示,其中25'h00061A7转换为16进制,即为我们改过的25'd24_999。