计数器counter
实验目标:每个时钟周期加一,在实验中采用50Mhz的时钟,即一秒钟计数50M-1个/或0.5s计数25M-1个。同时利用LED小灯在0.5s熄灭,后0.5s点亮。
实验框图与波形图:
实验代码
module counter
#(
parameter CNT_MAX=25'd24_999_999
)
(
input wire sys_clk,
input wire sys_rst_n,
output reg led_out
);
reg [24:0] cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=25'd0;
else if(cnt==CNT_MAX)
cnt<=25'd0;
else
cnt<=cnt+25'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
led_out <= 1'b0;
else if(cnt==CNT_MAX)
led_out <= ~led_out;
else
led_out <= led_out;
endmodule
参数设定的两种方式
将某些参数统一以提前声明的方式进行定义,即用parameter来定义一个标识符来代表一个常量,称为符号常量,即标识符形式的常量,采用标识符代表一个常量可以提高程序的可读性和可维护性。另一个很有用的用途就是可以利用defparam或者在模块实例化的时候进行参数传递(即重写)。
//方法一
parameter CNT_MAX=25'd24_999_999;
//方法二
#(
parameter CNT_MAX=25'd24_999_999,
)//这种写法可以在实例化中参数传递的一个接口 */
对应两种方法在实例化中的修改
//方法一
defparam counter_inst.CNT_MAX = 25'd1000;
//方法二
counter
#(
.CNT_MAX(1000)//在实例化中按照一个接口进行赋值
)
counter_inst//同时这里实例化名称位置有所不同
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
. led_out( led_out)
);
同时值得注意是的,例如设定了1000,此处1000仅作为减少仿真时间,与设定的上板时间定义的24_999_999没关系,。
仿真代码
`timescale 1ns/1ns
module tb_counter();
reg sys_clk;
reg sys_rst_n;
wire led_out;
initial
begin
sys_clk=1'b1;
sys_rst_n <=1'b0;
#20
sys_rst_n<=1'b1;
end
always #10 sys_clk=~sys_clk;
initial
begin
$timeformat(-9,0,"ns",6);
$monitor("@time %t:led_out=%b",$time,led_out);
end
counter
#(
.CNT_MAX(25'd24)
)
counter_inst
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
. led_out( led_out)
);
endmodule
timescale的使用
timescale是Verilog HDL 中的一种时间尺度预编译指令,它用来定义模块的仿真 时的时间单位和时间精度。格式如下:
`timescale 仿真时间单位/时间精度
注意:用于说明仿真时间单位和时间精度的 数字只能是1、10、100,不能为其它的数字。而且,时间精度不能比时间单位还要大。最多两则一样大。比如:下面定义都是对的:
`timescale 1ns/1ps
`timescale 100ns/100ns
下面的定义是错的:
`timescale 1ps/1ns
在verilog中是没有默认timescale的,一个没有指定timescale的verilog模块就有可能错误的继承了前面编译模块的无效timescale参数。