因为Basys3开发板只有4位数码管,而且中间的那个冒号无法显示。所以我们做4位的时间显示,min:sec或者hour:min。
然后我们如何去实现这个呢?首先需要利用系统时钟来计时,每秒或者每分钟变换一次,需要进位时进位,以及将数字显示出来。
因为时钟是动态的所以需要动态刷新,而人眼在每秒26帧以上时,会因为视觉暂留效应认为是连续变换的。也就是一个数码管至少一秒应该刷新26次以上,4位数码管至少应该是102Hz以上的刷新频率。
而BASYS3开发板的系统时钟的频率为50MHz或者100MHz。所以应该高频率的系统时钟分为低频的刷新时钟。而分频方式有2分频还有整数分频等方式。
这里使用整数分频,即系统时钟变换N次时,让输出脉冲变化一次。
注意:因为Verilog语言中 if 必须和 else 配对,不能只有if,不然会报错。
module clkdiv(
input clk,
input pau,
input res,
output reg clk100
);
parameter update_interval = 50000000 / 100 - 1;
integer selcnt;
reg state;
always @(posedge clk,posedge pau,posedge res) //100Hz
begin
if(res)
begin
state<=0;
selcnt<=0;
clk100<=0;
end
else if(pau)
state=~state;
else begin
if(state)
begin
if (selcnt == update_interval)
begin
selcnt <= 0;
clk100 <=~clk100;
end
else
selcnt<=selcnt+1;
end
else
selcnt<=selcnt+0;
end
end
endmodule
输入为系统的时钟,res重置按钮/开关,pau暂停按钮/开关。这里update_interval代表的是分频值的大小,要分成100Hz。系统时钟每有update_interval个上升沿时输出脉冲发生一次变化,即完成分频。res表示reset,时间置0。而pau表示pause,暂停,按下第一次时,会认为是暂停,selcnt一直加0,从而使时间暂停。按下第二次之后,state取反,继续计数。
输入为分频模块的输出的分频后的时钟脉冲,重置,输出为时间。代码为
module count(
input clk100,
input res,
output [15:0]tim
);
integer q;
reg[3:0]sec_0;
reg[3:0]sec_1;
reg[3:0]min_0;
reg[3:0]min_1;
always@(posedge clk100 or posedge res)
begin
if(res)begin
q<=0;
sec_1=4'b0000;
sec_0=4'b0000;
min_0=4'b0000;
min_1=4'b0000;
end
else begin
if(q==100)begin
q<=0;
if(sec_0==4'b1001) begin
sec_0<=4'b0000;
if(sec_1==4'b0101)begin
sec_1<=4'b0000;
if(min_0==4'b1001)begin
min_0<=4'b0000;
if(min_1==4'b0101)
min_1<=4'b0000;
else
min_1<=min_1+1;
end
else
min_0<=min_0+1;
end
else
sec_1<=sec_1+1;
end
else
sec_0<=sec_0+1;
end
else
q<=q+1;
end
end
assign tim={min_1,min_0,sec_1,sec_0};
endmodule
为什么这里没有把pau作为输入呢?因为时间的值是随着输入时钟变化的,而pause之后,分频模块里的时钟已经不再增加了,所以计数模块的值也不会发生变化了。
普通的7段数码显示
module display(
inout clk,
input [15:0]tim,
output reg[3:0] an,
output reg[6:0] a_to_g
);
reg[1:0] sign;
reg[3:0] digit;
parameter update_interval = 50000000 / 160 - 1;
integer selcnt;
always @(posedge clk) //分频160Hz
begin
selcnt <= selcnt + 1;
if (selcnt == update_interval)
begin
selcnt <= 0;
sign <= sign+ 1;
end
end
always @(*) //选择位
case(sign)
0:begin an=4'b1110;digit=tim[3:0];end
1:begin an=4'b1101;digit=tim[7:4];end
2:begin an=4'b1011;digit=tim[11:8];end
3:begin an=4'b0111;digit=tim[15:12];end
endcase
always @(*)//显示段数
case(digit)
0:a_to_g=7'b0000001;
1:a_to_g=7'b1001111;
2:a_to_g=7'b0010010;
3:a_to_g=7'b0000110;
4:a_to_g=7'b1001100;
5:a_to_g=7'b0100100;
6:a_to_g=7'b0100000;
7:a_to_g=7'b0001111;
8:a_to_g=7'b0000000;
9:a_to_g=7'b0000100;
'hA:a_to_g=7'b0001000;
'hB:a_to_g=7'b1100000;
'hC:a_to_g=7'b0110001;
'hD:a_to_g=7'b1000010;
'hE:a_to_g=7'b0110000;
'hF:a_to_g=7'b0111000;
default:a_to_g=7'b0000001;
endcase
endmodule
module timer(
input clk,
input [1:0] btn,
output [3:0] an,
output [6:0] a_to_g,
output dp
);
wire clk100;
wire [15:0]tim;
assign dp=1'b1;
clkdiv ck(.clk(clk),
.pau(btn[0]),
.res(btn[1]),
.clk100(clk100));
count ct(.clk100(clk100),
.res(btn[1]),
.tim(tim));
display dis(.clk(clk),
.tim(tim),
.an(an),
.a_to_g(a_to_g));
endmodule
如下,限制文件可能会报“ambiguous clock”这个问题,这个要注释一句就好了,百度上好像有。这里不粘出来了。