1. 代码
module TimeCount
(
CLK_50M,RST_N,
time_cnt
);
//-- 外部端口声明
input CLK_50M,RST_N;
output reg [19:0] time_cnt;
//-- 内部端口声明
reg [19:0] time_cnt_n; //time_cnt 的下一个状态
//设置定时器的时间为20ms,计算方法为 (20*10^3)us / (1/50)us 50MHz为开发板晶振
parameter SET_TIME_20ms = 20'd1_000_000;
//parameter SET_TIME_20ms = 20'd1_0; //仿真用
//---------------------------------------------------------------------------
//-- 逻辑功能实现
//---------------------------------------------------------------------------
//时序电路,给 time_cnt 寄存器赋值。将次态赋值给现态
always @ (posedge CLK_50M or negedge RST_N)
begin
if (!RST_N) //判断复位
time_cnt <= 20'd0; //初始化 time_cnt 值
else
time_cnt <= time_cnt_n; //用来给 time_cnt 赋值
end
//组合电路,实现 1s 的定时计数器。次态的逻辑
always @ (*)
begin
if (time_cnt == SET_TIME_20ms -1'b1)
time_cnt_n = 20'd0; //如果到达 1s,定时计数器将会被清零
else
time_cnt_n = time_cnt + 1'b1; //如果未到 1s,定时计数器将会继续累加
end
endmodule
用Quartus自带的波形仿真器仿真
2. 分析
特点:组合和时序电路分开,这样写有什么好处呢?
1、是时序电路用非阻塞赋值(<=),组合电路用阻塞赋值(=),一下就能分清楚。
2、是当工程很大时,分析起来很有优势,因为时序逻辑部分的写法几乎是完全一样的,这时就可以将主要精力放在分析组合逻辑上面。
问题:组合电路能实现计数器吗?如果只是实现一次加的运算,那组合电路是可以的,这里借助寄存器来把每一次加 1 的结果保存下来,下一次加 1 就是累加的了。
“一次加”的确切含义是什么?
3 应用
生成rst信号
产生rst信号,1:置位;0:工作
- 师兄代码
input wire refclk;
output reg rst;
reg [2:0] rst_cnt = 0;
always@(posedge refclk) begin
if(rst_cnt[2] == 1) begin
rst_cnt <= rst_cnt;
rst <= 0;
end
else begin
rst_cnt <= rst_cnt+1'b1;
rst <= 1;
end
end
- 我的代码
将组合与逻辑电路分开
input wire refclk;
output reg rst;
reg [2:0] time_cnt=3'd0;
reg [2:0] time_cnt_n=3'd0;
always@ (posedge refclk)
begin
time_cnt <= time_cnt_n;
end
always@ (*)
begin
if(time_cnt[2] == 1'b1)
begin
time_cnt_n = time_cnt;
//计数器在这里归零,循环计数。这里需要保持,停止计数。
rst = 1'b0;
end
else
begin
time_cnt_n = time_cnt + 1'b1;
rst = 1'b1;
end
end
4 技巧
- 利用计数溢出造成的截位,省略判断置零语句,这样在高速情况下更稳定(张总说法)。可用在适当的分频中。比如需要0.5M时钟,利用PLL产生4M进而0~7计数,八分频。
output reg [2:0] cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 0;
else
cnt <= cnt +1;
计数到111时,下一次计数本来是1000,但cnt只有3位,编程000,又重新开始计数。