本文主要是介绍基于BASYS3开发板Verilog的计时器实验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
基于BASYS3开发板Verilog的计时器实验
因为Basys3开发板只有4位数码管,而且中间的那个冒号无法显示。所以我们做4位的时间显示,min:sec或者hour:min。
然后我们如何去实现这个呢?首先需要利用系统时钟来计时,每秒或者每分钟变换一次,需要进位时进位,以及将数字显示出来。
1. 分频模块
因为时钟是动态的所以需要动态刷新,而人眼在每秒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) //100Hzbeginif(res)beginstate<=0;selcnt<=0;clk100<=0;endelse if(pau)state=~state;else beginif(state)begin if (selcnt == update_interval) begin selcnt <= 0; clk100 <=~clk100; endelseselcnt<=selcnt+1;endelseselcnt<=selcnt+0;end endendmodule
输入为系统的时钟,res重置按钮/开关,pau暂停按钮/开关。这里update_interval代表的是分频值的大小,要分成100Hz。系统时钟每有update_interval个上升沿时输出脉冲发生一次变化,即完成分频。res表示reset,时间置0。而pau表示pause,暂停,按下第一次时,会认为是暂停,selcnt一直加0,从而使时间暂停。按下第二次之后,state取反,继续计数。
2.计数模块
输入为分频模块的输出的分频后的时钟脉冲,重置,输出为时间。代码为
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)beginif(res)beginq<=0;sec_1=4'b0000;sec_0=4'b0000;min_0=4'b0000;min_1=4'b0000;endelse beginif(q==100)beginq<=0;if(sec_0==4'b1001) begin sec_0<=4'b0000;if(sec_1==4'b0101)beginsec_1<=4'b0000;if(min_0==4'b1001)begin min_0<=4'b0000;if(min_1==4'b0101)min_1<=4'b0000;elsemin_1<=min_1+1; endelsemin_0<=min_0+1; endelsesec_1<=sec_1+1; endelsesec_0<=sec_0+1; endelseq<=q+1; end endassign tim={min_1,min_0,sec_1,sec_0};
endmodule
为什么这里没有把pau作为输入呢?因为时间的值是随着输入时钟变化的,而pause之后,分频模块里的时钟已经不再增加了,所以计数模块的值也不会发生变化了。
3.显示模块
普通的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) //分频160Hzbegin selcnt <= selcnt + 1; if (selcnt == update_interval) begin selcnt <= 0; sign <= sign+ 1; end endalways @(*) //选择位case(sign)0:begin an=4'b1110;digit=tim[3:0];end1:begin an=4'b1101;digit=tim[7:4];end2:begin an=4'b1011;digit=tim[11:8];end3:begin an=4'b0111;digit=tim[15:12];endendcasealways @(*)//显示段数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;endcaseendmodule
4.模块组合
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”这个问题,这个要注释一句就好了,百度上好像有。这里不粘出来了。
这篇关于基于BASYS3开发板Verilog的计时器实验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!