掌握两点:控制好什么时候开始计数和什么时候清零的问题
一:系统只有时钟和复位信号,只要复位信号一撤销,时钟沿来到就可以立刻进行计数。
二:计满自动清零,计数到多少后进行清零呢?假设时钟信号的频率为50MHz,也就是时钟周期为20ns,那么计时1s中,需要多少个时钟周期呢?1s/20ns =50_000_000个。因为是从0开始计数,所以计数到49_999_999之后清零。利用计算器(程序员模式)可知,计算器的位数要设为26位。就是49_999_999转换成二进制表示。
不带标志信号的计数器
module cnt
#(
parameter CNT_MAX = 24999_999
)
(
input wire sclk ,
input wire rst_n ,
output reg led_out
);
reg [24:0] cnt;
//cnt:计数器计数到最大值时清零
always@(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt <= 25'd0;
else if(cnt == CNT_MAX)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
//当计数到最大值时,取反
always@(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
led_out <= 1'b0;
else if(cnt == CNT_MAX)
led_out <= ~led_out;
endmodule
`timescale 1ns/1ns
module tb_cnt();
reg sclk, rst_n;
wire led_out;
initial begin
sclk <= 1'b0;
rst_n <= 1'b0;
#20
rst_n <= 1'b1;
end
always #10 sclk <= ~sclk;
cnt
#(
.CNT_MAX (25'd24)
)
cnt_inst
(
.sclk (sclk),
.rst_n (rst_n),
.led_out (led_out)
);
endmodule
带标志信号的计数器
脉冲标志信号(flag),这种信号会在后面用到很多,它可以减少代码中if括号内的条件让代码更加清晰简洁,而且当需要在多处使用脉冲标志信号的地方要比全部写出的方式更节约逻辑资源,脉冲标志信号在指示某些状态时是非常有用的,当大家以后在实现相对复杂的逻辑功能时注意想到使用脉冲标志信号,后面我们还会介绍到另一个有用的信后——使能信号。
小细节:led_out信号拉高的条件时以cnt_flag为条件变化的,要使得cnt_flag在计数器计数到N-1时就拉高。
module cnt1
#(
parameter CNT_MAX = 24999_999
)
(
input wire sclk ,
input wire rst_n ,
output reg led_out
);
reg [24:0] cnt;
reg cnt_flag;
//计数器
always@(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt <= 25'd0;
else if(cnt == CNT_MAX)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
//当计数到N-1时,cnt_flag拉高
always@(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt_flag <= 1'b0;
else if(cnt == CNT_MAX-1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
//当cnt_flag拉高时,led_out取反
always@(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
led_out <= 1'b0;
else if(cnt_flag == 1'b1)
led_out <= ~led_out;
endmodule