题目:请用Verilog RTL描述如下图设计:以clk为基准,设计一个秒计数器,在指定的计数值产生中断,实时输出当前的秒数计数值。
<1>clk是时钟输入,频率为32.768KHz。
<2>rst_n是异步复位输入,低电平有效,复位整个系统,为高则整个系统开始工作,其上升沿已经同步于clk。
<3>start是启动信号,一个clk时钟周期的正脉冲,同步于clk。alarm[7:0]是配置信息,单位为秒,同步于clk。
<4>工作模式:收到start后,秒计数器sec_cnt从零开始以秒为单位来计数,计数到alarm[7:0]指定的数值时,产生一个int pluse(时钟周期的正脉冲),秒数计数器回零并停止。
根据题目进行思考:
1.设计一个1秒的计数器,可以利用系统时钟的频率,从0开始计数,当计数到32767时则完成1秒的计数。
2.异步复位,低电平有效即:
always@(posedge clk or negedge rst_n)
3.有一个statrt启动脉冲信号,当start=1时,开始进行计数。
4.alarm[7:0],即当sec_cnt=alarm时,int产生一个脉冲信号。假设alrm=3,即当计数满3秒的时候,int产生一个脉冲信号,秒数计数器返回0并停止。
分析:
1.由于start是一个脉冲信号,所以不能精确的控制计数的开始与结束,所以用一个cnt_en来控制计数的开始与结束。
2.用cnt_1s作为计数为1秒的计数器。
3.异步复位导致改变要慢一个时钟周期
波形图如下
module sec_cnt_top
#(
parameter cnt_1s_max=16'd32767
)
(
input wire clk,
input wire rst_n,
input wire start,
input wire[7:0]alarm,
output reg int1,
output reg [31:0]sec_cnt
);
reg cnt_en;
reg [14:0]cnt_1s;
always@(posedge clk or negedge rst_n)//使能端赋值
if(rst_n==1'b0)
cnt_en<=1'b0;
else if(start==1'b1)
cnt_en<=1'b1;
else if((cnt_1s==cnt_1s_max)&&(sec_cnt==alarm))
cnt_en<=1'b0;
else
cnt_en<=cnt_en;
always@(posedge clk or negedge rst_n)//时间为1s的计数器
if(rst_n==1'b0)
cnt_1s<=15'd0;
else if(cnt_1s==cnt_1s_max)
cnt_1s<=15'd0;
else if(cnt_en==1'b1)
cnt_1s<=cnt_1s+15'd1;
else
cnt_1s<=1'b0;
always@(posedge clk or negedge rst_n)//产生的时钟脉冲
if(rst_n==1'b0)
int1<=1'b0;
else if((cnt_1s==cnt_1s_max)&&(sec_cnt==alarm))
int1<=1'b1;
else
int1<=1'b0;
always@(posedge clk or negedge rst_n)//记录一共产生了多少个1s
if(rst_n==1'b0)
sec_cnt<=32'd0;
else if((cnt_1s==cnt_1s_max)&&(sec_cnt==alarm))
sec_cnt=32'd0;
else if(cnt_1s==cnt_1s_max-1'b1)
sec_cnt<=sec_cnt+32'd1;
else
sec_cnt<=sec_cnt;
endmodule
下面是测试代码
`timescale 1ns / 1ns
module tb_sec_cnt_top();
reg clk;
reg rst_n;
reg start;
reg [7:0]alarm;
wire int1;
wire [31:0]sec_cnt;
initial
begin
clk=1'b1;
rst_n<=1'b0;
start<=1'b0;
alarm<=8'b0;
#20
rst_n<=1'b1;
end
initial
begin
#40
start<=1'b1;
alarm<=8'd3;
#20
start<=1'b0;
#5000
start<=1'b1;
alarm<=8'd4;
#20
start<=1'b0;
end
always #10 clk=~clk;
sec_cnt_top
#(
.cnt_1s_max(16'd49)//便于仿真
)
sec_cnt_top_inst
(
.clk(clk),
.rst_n(rst_n),
.start(start),
.alarm(alarm),
.int1(int1),
.sec_cnt(sec_cnt)
);
endmodule
vivado仿真波形分析
各变量初值以及收到start脉冲时使能端为1
当计数到alarm时,产生一个周期的时钟脉冲int1(为了仿真,故将计数最大值设置为49),记录一次结束后遍停止计数,等待下一次start信号出现再继续工作。
收到start信号,重新开始计数
记满时产生一个周期的时钟脉冲
整体波形图如下(测试代码中第二次start改为#4000)