5 - 时序逻辑代码设计与仿真
秒计数器(0-9 循环计数)
把系统时钟进行分频,得到秒脉冲,对秒脉冲进行计数。
con_t 是秒脉冲分频计数器,需要对 24M 来计数,至少需要 25 位。
s_pulse 是秒脉冲尖,con_t 为 0 时为1,1 秒有 24M 个脉冲,但只有 1 个脉冲时 s_pulse=1。
s_num 是秒计数器,看到 s_pulse 为 1 时计数。
//2021.11.19 lyw
//Second counter 0-9 cycles
`timescale 1ns/10ps
module s_counter (
clk,
res,
s_num
);
input clk;
input res;
output[3:0] s_num;
parameter frequency_clk = 24; //24MHz
reg[24:0] con_t; //Second pulse frequency division counter
reg s_pulse; //Second pulse tip
reg[3:0] s_num;
always @(posedge clk or negedge res) begin
if(~res) begin
con_t<=0;
s_pulse<=0;
s_num<=0;
end
else begin
//without 'if' con_t will be 0 until overflow rather than 24M
if (con_t == frequency_clk*1000000-1) begin
con_t<=0;
end
else begin
con_t<=con_t+1;
end
if (con_t==0) begin
s_pulse<=1;
end
else begin
s_pulse<=0;
end
if (s_pulse) begin
if (s_num==9) begin
s_num<=0;
end
else begin
s_num<=s_num+1;
end
end
end
end
endmodule
//----testbench of s_counter----
module s_counter_tb;
reg clk;
reg res;
wire[3:0] s_num;
s_counter s_counter (
.clk(clk),
.res(res),
.s_num(s_num)
);
initial begin
clk<=0;
res<=0;
#17 res<=1;
#1000 $stop;
end
always #5 clk=~clk;
endmodule
PS:所有的 if…else 都必须写在 always 里面否则会编译报错。
仿真波形
刚从 0 计数到 1,仿真就结束了。
因为 #1000 $stop; 里面的 1000 选的太短了,如何选择合适的时长?
点击 【continue run】+【break】继续画波形,因为 clk 太密了,把 clk 删掉画波形会更快。
但画完以后还是计数到 1,因为 24M 实在太大了,很难仿真完,这里把分频系数改小 1000 倍。
改完 reload,重新编译,并配合【continue run】+【break】。
同时也得到了合适的时间,修改时间后重新画图。
可以从图中观察得到:每过24000个时钟周期,s_pulse 出现一个 1,s_num 进行一次计数。(变化后下一个时钟上升沿才能看到)
在放大的过程中需要用到的两个功能:
上面的框是局部放大,选择一块区域放大;下面的框是以金色的线为中心放大。
数码管 0-9 秒显示
数码管 0-59 秒显示
本节有个问题是关于秒计数器
24MHz 即 24000000 个时钟为 1 秒,那一个时钟周期应该会是 1/24000000 秒,所以`timescale 1ns 这里是不是要改成1000/24。
学习内容总结自网络,主讲教师北交李金诚。