Verilog数字钟设计(开发板实际验证,含演示视频)

  1. 本博客的数字钟采用的是开关方法,若想了解按钮方法,可阅读完这篇博客,转向我的另一篇博客https://blog.csdn.net/qq_42181309/article/details/90637339
  2.  数字钟网上有很多的方法,写的呢仅供参考。主要是分享一下思路。验证是在xilinx vivado套件选择xc7a100tcsg324-1的开发板下验证的。就是学生实验教学用的开发板。
  3. 首先是功能构想,数字钟应该有什么功能。整体功能:数码管一共是8个的对吧,要用到其中6个。分别显示时分秒位。然后有个校时功能。那再细分一下,要实现这个整体功能,需要什么呢。
  • 首先要有俩分频模块,第一个分频用于计时,即每秒进位,然后带动分位,带动小时位,你也可以说它是计时模块。另外一个分频模块,因为多个数码管显示运用的视觉停留的原理,所以要分频用于数码管的显示。
  • 其次就是译码模块,为什么要译码?因为计时的时候,你用简单的加法,方便计数。但显示的时候,比如数字7,你需要的是一个8位宽的序列。所以我们要译码。这里有一个考量,用六个译码器还是一个译码器?六个译码器,即对时分秒位,每个位两个数字,如13:59:59,同时译码。一个译码器就是在分频显示的时候再译码,比如你要显示13:59:59里的5的时候再对5的位置译码,即先决定显示哪位再译码。这个方法很省资源。但初学者的我,没控制好时许。所以最后只好采用6个译码器。
  • 还有三注意事项,就是非法值检验和小数点了。13:59:57。需要在3和9位显示小数点。这也是我采用6个译码器的原因。你只要在分频显示的时候显示到3或者9的时候,改下小数点。还有非法检验,比如你要校准为25:59:59,这铁定是不能让你输入的。这加点预处理就行。
  • 最后一个注意事项是划分模块一定要细,如果采用行为级描述,心里要有个底,最好写tb文件验证,因为ADT工具不是很好,想像C语言那样你可就大错特错了。
  • 到这基本原理就结束了,下面是具体实现。
  • 这是我的实现方式,需要用IO口有11个,4个din用于确保数字0到9(BCD),6位ctl用来决定你是要矫正哪位,其它5位就保持不动,所以这是个时许电路,时钟上升沿加载。第一个outputreset模块,输出校准后的时分秒,r_cal模块是二次矫正,为什么要二次矫正比如你矫正完位27:11:12,二次矫正后就为23:11:12,即非法检验。
  • 接着就到了cnt计时模块,我将reset信号用于加载信号,如果reset就加载矫正后的值,当reset为0时,从当前值开始计数。
  • cnt模块连着6个译码器decode模块,即同时译码。之后seegctl通过分频来分别显示时分秒位。注意译码器是7位的,即我们没决定小数点是否显示,而是在seegctl决定的,其实译码那里决定也可以。都行,仅供参考。
  • 下面是参考源代码
  • .top,主要用于模块的连接
module top(
	input clk,
	input reset,
	input [3:0] din,
	input [5:0]ctl,
	output [6:0] seeg,
	output [7:0] sctl,
	output seeg_p
    );
	wire [6:0]decode_hh;
	wire [6:0]decode_hl;
	wire [6:0]decode_mh;
	wire [6:0]decode_ml;
	wire [6:0]decode_sh;
	wire [6:0]decode_sl;
	wire [3:0] second_l;
	wire [3:0] second_h;
	wire [3:0]minute_l;
	wire [3:0]minute_h;
	wire [3:0]hour_l;
	wire [3:0]hour_h;
	wire [3:0] second_l_r;
	wire [3:0] second_h_r;
	wire [3:0]minute_l_r;
	wire [3:0]minute_h_r;
	wire [3:0]hour_l_r;
	wire [3:0]hour_h_r;
    wire [3:0] second_ll;
	wire [3:0] second_hh;
	wire [3:0]minute_ll;
	wire [3:0]minute_hh;
	wire [3:0]hour_ll;
	wire [3:0]hour_hh;
output_reset output_reset(.clk(clk),.din(din),.ctl(ctl),.second_l_r(second_l_r),.second_h_r(second_h_r),.minute_l_r(minute_l_r),.minute_h_r(minute_h_r),.hour_l_r(hour_l_r),.hour_h_r(hour_h_r));
output_r_cal r_cal(.second_l_r(second_l_r),.second_h_r(second_h_r),.minute_l_r(minute_l_r),.minute_h_r(minute_h_r),.hour_l_r(hour_l_r),.hour_h_r(hour_h_r),.second_ll(second_ll),.second_hh(second_hh),.minute_ll(minute_ll),.minute_hh(minute_hh),.hour_ll(hour_ll),.hour_hh(hour_hh));
cnt cnt(.reset(reset),.clk(clk),.second_ll(second_ll),.second_hh(second_hh),.minute_ll(minute_ll),.minute_hh(minute_hh),.hour_ll(hour_ll),.hour_hh(hour_hh),.hour_h(hour_h),.hour_l(hour_l),.minute_h(minute_h),.minute_l(minute_l),.second_h(second_h),.second_l(second_l));
 decode h_h(.v(hour_h),.seegs(decode_hh));
 decode h_l(.v(hour_l),.seegs(decode_hl));
 decode m_h(.v(minute_h),.seegs(decode_mh));
 decode m_l(.v(minute_l),.seegs(decode_ml));
 decode s_h(.v(second_h),.seegs(decode_sh));
 decode s_l(.v(second_l),.seegs(decode_sl));
seegctl(.decode_hh(decode_hh),.decode_hl(decode_hl),.decode_mh(decode_mh),.decode_ml(decode_ml),.decode_sh(decode_sh),.decode_sl(decode_sl),.clk(clk),.seeg(seeg),.sctl(sctl),.seeg_p(seeg_p));
endmodule

output_reset,我在这里让输入校正只能为0到9,

module output_reset(
     input clk,
	 input [3:0] din,
     input [5:0]ctl,
     output reg [3:0] second_l_r,
	 output reg [3:0] second_h_r,
	 output reg [3:0]minute_l_r,
	 output reg [3:0]minute_h_r,
	 output reg [3:0]hour_l_r,
	 output reg [3:0]hour_h_r
    );
	reg[5:0] ctl_one;
	reg[5:0] ctl_two;
	reg [3:0]q;
	reg[3:0]q1;
	reg[3:0]q2;
	always @*
	if(din<10)
	q=din;
	else
	q=din-8;
	always @(posedge clk)
	begin
	ctl_one<=ctl;
	ctl_two<=ctl_one;
	q1<=q;
	q2<=q1;
	end
	always @(posedge clk)
        if(ctl_two[5]==1'b1)
        hour_h_r<=q2;
        else if(ctl_two[4]==1'b1)
        hour_l_r<=q2;
        else if(ctl_two[3]==1'b1)
        minute_h_r<=q2;
        else if(ctl_two[2]==1'b1)
        minute_l_r<=q2;
        else if(ctl_two[1]==1'b1)
        second_h_r<=q2;
        else if(ctl_two[0]==1'b1)
        second_l_r<=q2;
endmodule
module output_r_cal(
     input [3:0] second_l_r,
	 input [3:0] second_h_r,
	 input [3:0]minute_l_r,
	 input [3:0]minute_h_r,
	 input [3:0]hour_l_r,
	 input [3:0]hour_h_r,
	 output [3:0] second_ll,
	 output [3:0] second_hh,
     output [3:0]minute_ll,
	 output [3:0]minute_hh,
	 output [3:0]hour_ll,
	 output [3:0]hour_hh
    );
	assign hour_hh=(hour_h_r>2)? {3'b00,hour_h_r[0]}:hour_h_r;
	assign hour_ll=(hour_h_r==2)? {2'b00,hour_l_r[1:0]}:hour_l_r;
	assign minute_hh=(minute_h_r>5) ? {2'b0,minute_h_r[1:0]}:minute_h_r;
	assign minute_ll=minute_l_r;
	assign second_hh=(second_h_r>5) ? {2'b0,second_h_r[1:0]}:second_h_r;
	assign second_ll=second_l_r;
endmodule

cnt,分频频率根据你板子的时钟频率来设置,我用的板子是100Whz的,所以我分频基数就为10**8。

module cnt(
    input clk,
	input reset,
	 input  [3:0] second_ll,
	 input  [3:0] second_hh,
	 input  [3:0]minute_ll,
	 input  [3:0]minute_hh,
	 input  [3:0]hour_ll,
	 input  [3:0]hour_hh,
	 output reg [3:0] second_l,
	 output reg [3:0] second_h,
	 output reg [3:0]minute_l,
	 output reg [3:0]minute_h,
	 output reg [3:0]hour_l,
	 output reg [3:0]hour_h
    );
	parameter ST_N=30;//秒表分频频率N
	reg [ST_N-1:0] wa_clk;//秒表分频时钟
	reg reset_one;
	reg reset_two;
	reg  [3:0] second1_ll;
	reg  [3:0] second1_hh;
	reg  [3:0]minute1_ll;
	reg  [3:0]minute1_hh;
	reg  [3:0]hour1_ll;
	reg  [3:0]hour1_hh;
	reg  [3:0] second2_ll;
	reg  [3:0] second2_hh;
	reg  [3:0]minute2_ll;
	reg  [3:0]minute2_hh;
	reg  [3:0]hour2_ll;
	reg  [3:0]hour2_hh;
always @(posedge clk)
begin
second1_ll<=second_ll;
second2_ll<=second1_ll;
second1_hh<=second_hh;
second2_hh<=second1_hh;
minute1_ll<=minute_ll;
minute2_ll<=minute1_ll;
minute1_hh<=minute_hh;
minute2_hh<=minute1_hh;
hour1_ll<=hour_ll;
hour2_ll<=hour1_ll;
hour1_hh<=hour_hh;
hour2_hh<=hour1_hh;
reset_one<=reset;
reset_two<=reset_one;
end
always @(posedge clk)//计时
if(reset_two)
begin
hour_h<=hour2_hh;
hour_l<=hour2_ll;
minute_h<=minute2_hh;
minute_l<=minute2_ll;
second_h<=second2_hh;
second_l<=second2_ll;
wa_clk<=0;
end
else
	if(wa_clk<(10**8))
		wa_clk<=wa_clk+1;
	else
			 begin
			wa_clk<={ST_N-1'b0,1'b1};//时钟复位
				 begin
				 if(second_l<9)
					 second_l<=second_l+1;
				 else
					 begin
					 second_l<=0;//复位
					 if(second_h<5)
						 second_h<=second_h+1;
					 else
						 begin
						 second_h<=0;
						 if(minute_l<9)
							 minute_l<=minute_l+1;
						 else
							 begin
							 minute_l<=0;//复位
							 if(minute_h<5)
								minute_h<=minute_h+1;
							 else
								 begin
								 minute_h<=0;//复位
								 
								 if((hour_h<2)&&(hour_l<9))
									hour_l<=hour_l+1;
								 else if((hour_h==4'b0010)&&(hour_l<3))
									hour_l<=hour_l+1;
								 else if((hour_h==4'b0010)&&(hour_l==3))//过了一天重新开始
										begin
										hour_l<=0;
										hour_h<=0;
										minute_l<=0;
										minute_h<=0;
										second_l<=0;
										second_h<=0;
										end
									 else
										 begin
										 hour_l<=0;//复位
										 hour_h<=hour_h+1;
										 end
								 end
							 end
						 end
					 end
				 end
			 end
	endmodule

译码器

module decode(
    input [3:0] v,
    output reg [6:0] seegs
    );
 always @*
  begin
   if(v==4'h0)
   seegs=7'b1000000;
 else if(v==4'h1)
 seegs=7'b1111001;
  else if(v==4'h2)
  seegs=7'b0100100;
   else if(v==4'h3)
   seegs=7'b0110000;
   else if(v==4'h4)
   seegs=7'b0011001;
   else if(v==4'h5)
   seegs=7'b0010010;
   else if(v==4'h6)
   seegs=7'b0000010;
   else if(v==4'h7)
   seegs=7'b1111000;
   else if(v==4'h8)
   seegs=7'b0000000;
   else
   seegs=7'b0010000;  
 end
 endmodule

seegctl,主要用于控制数码管的显示,由sctl,seeg和seep_p16位共同控制

module seegctl(
	input clk,
	input wire [6:0]decode_hh,
	input wire [6:0]decode_hl,
	input wire [6:0]decode_mh,
	input wire [6:0]decode_ml,
	input wire [6:0]decode_sh,
	input wire [6:0]decode_sl,
	output reg [7:0]sctl,
	output reg [6:0]seeg,
	output reg seeg_p
    );
	 parameter SEEG_N=19;//数码管分频频率N
	reg [SEEG_N-1:0] seeg_clk;//数码管分频时钟
	initial
	begin
	end
	always @(posedge clk)//数码管分频,一共需要7个数码管所以分三位,sctl0位对应数码管亮的位置
     begin
     seeg_clk<=seeg_clk+1;
     if(seeg_clk[SEEG_N-1:SEEG_N-3]==3'b111)
     seeg_clk<=0;
     end
     always@*
    if(seeg_clk[SEEG_N-1:SEEG_N-3]==3'b010)
        begin
        sctl=8'b11111110;
		seeg=decode_sl;
        seeg_p=1;
        end
     else if(seeg_clk[SEEG_N-1:SEEG_N-3]==3'b011)
        begin
         sctl=8'b11111101;
		seeg=decode_sh;
         seeg_p=1;
        end
     else if(seeg_clk[SEEG_N-1:SEEG_N-3]==3'b100)
        begin
         sctl=8'b11111011;
		seeg=decode_ml;
         seeg_p<=0;
        end
     else if(seeg_clk[SEEG_N-1:SEEG_N-3]==3'b101)
        begin
         sctl=8'b11110111;
		seeg=decode_mh;
         seeg_p=1;
        end
     else if(seeg_clk[SEEG_N-1:SEEG_N-3]==3'b110)
        begin
         sctl=8'b11101111;
		seeg=decode_hl;
         seeg_p=0;
        end
     else
        begin
         sctl=8'b11011111;
		 seeg<=decode_hh;
		 seeg_p<=1;
        end
endmodule

运行效果,由于没有不能上传视频只能附图

补充:

约束文件IO管脚设置没给出,然后这仅供刚开始学习verilog想做数字钟的同学或者其他人员参考,实现并不是很高效。源码可以随便用,转载请注明出处。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值