fpga基于AX301的时钟秒表设计

该代码展示了一个使用Verilog编写的多功能计时器设计,包括24小时制数字钟和电子秒表功能。设计中包含了时、分、秒的显示,以及秒表的清零、启动、暂停功能。模块包括顶层模块、计数秒表模块和数码管驱动模块,使用了按键消抖处理来提高稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使设计的多功能计时器包括数字钟和电子秒表的功能。数字钟电路部分具有时、分、秒显示功能,以24小时循环计时;具有调节小时、分钟功能。电子秒表部分计时部分具有清零、启动计时、暂停计时功能,板子是黑金的AX301

源代码

顶层模块

module top ( 
	input 			clk		,//系统时钟输入50M
	input			rst_n	,//复位,低电平有效

	output  	[5:0]	sel,
	output  	[7:0]	seg,
	input		 	key1	,
	input		 	key2	,
	input		 	key0	

 );




wire 	[23:0]	hex_data;
wire _2_flag;
wire _1_flag;
wire _0_flag;
xiaodou xiaodou2(.clk(clk),.rst_n(rst_n),.key1(key2),.key_out1(_2_flag));
xiaodou xiaodou1(.clk(clk),.rst_n(rst_n),.key1(key1),.key_out1(_1_flag));
xiaodou xiaodou0(.clk(clk),.rst_n(rst_n),.key1(key0),.key_out1(_0_flag));

counter  counter( 
	.clk	(clk)	,//系统时钟输入50M
	.rst_n(rst_n)	,//复位,低电平有效
	.key_time(_2_flag),
	.key_add(_1_flag)	,
	.key_sub(_0_flag)	,

	.hex_data(hex_data)	

 );
hex hex(
	.clk	(clk)	,//系统时钟输入50M
	.rst_n(rst_n)	,//复位,低电平有效
	.data_in(hex_data),	//待显示数据
	.point(6'b010100),	//待显示数据
	.sel(sel),
	.seg(seg)
);
endmodule  

计数秒表模块

module counter ( 
	input 				clk		,//系统时钟输入50M
	input				rst_n	,//复位,低电平有效
	input		 	key_time	,
	input		 	key_add	,
	input		 	key_sub	,

	output  	reg 	[23:0]	hex_data	

 );

reg		[25:0]	cnt_ns	; 
reg		[6:0]	cnt_s	; 
reg		[6:0]	cnt_min	; 
reg		[6:0]	cnt_h	;

reg		[19:0]	cnt_ns1	; 
reg		[3:0]	cnt_10ms;
reg		[3:0]	cnt_100ms;
reg		[5:0]	cnt_s1	;
reg		[5:0]	cnt_min1	; 
//生成修改时钟时的闪烁效果
//时钟分频,生成0.5s的时钟
reg	[25:0]	cnt_ns_half	; 
reg	flag_half	; 
reg out_flag;
reg		[3:0]	m_c_10ms;
reg		[3:0]	m_c_100ms;
reg		[5:0]	m_c_s1	;
reg		[5:0]	m_c_min1;
reg		[3:0]	c_10ms;
reg		[3:0]	c_100ms;
reg		[5:0]	c_s1	;
reg		[5:0]	c_min1;
wire[3:0] cnt_s_bcd1=cnt_s/10%10;
wire[3:0] cnt_min_bcd1=cnt_min/10%10;
wire[3:0] cnt_h_bcd1=cnt_h/10%10;
wire[3:0] cnt_s_bcd2=cnt_s%10;
wire[3:0] cnt_min_bcd2=cnt_min%10;
wire[3:0] cnt_h_bcd2=cnt_h%10;

wire[3:0] c_s1_bcd1=c_s1/10%10;
wire[3:0] c_s1_bcd2=c_s1%10;
wire[3:0] c_min1_bcd1=c_min1/10%10;
wire[3:0] c_min1_bcd2=c_min1%10;
localparam S_IDLE=     7'b0000_0001;  
localparam S_TIME=     7'b0000_0010; 
localparam S_HOUR=     7'b0000_0100;       
localparam S_MIN=      7'b0000_1000;     
localparam S_CNT=      7'b0001_0000;       
localparam S_CNT_RUN=  7'b0010_0000;      
localparam S_CNT_STOP= 7'b0100_0000;    
     
reg [6:0]state;

always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		state<=S_IDLE; 
	else 
		case(state)
		S_IDLE:state<=S_TIME;
		S_TIME:
			if(key_time)
				state<=S_HOUR;
			else if(key_sub)
				state<=S_CNT;
			else
				state<=S_TIME;
		S_HOUR:
			if(key_time)
				state<=S_MIN;
			else
				state<=S_HOUR;
		S_MIN:
			if(key_time)
				state<=S_TIME;
			else
				state<=S_MIN;
		S_CNT:
			if(key_sub)
				state<=S_TIME;
			else if(key_time)
				state<=S_CNT_RUN;
			else
				state<=S_CNT;
		S_CNT_RUN:
			if(key_time)//清零
				state<=S_CNT;
			else if(key_add)
				state<=S_CNT_STOP;
			else if(key_sub)
				state<=S_TIME;
			else 
				state<=S_CNT_RUN;
		S_CNT_STOP:
			if(key_add)
				state<=S_CNT_RUN;
			else if(key_time)
				state<=S_CNT;
			else if(key_sub)
				state<=S_TIME;
			else 
				state<=S_CNT_STOP;			
		default:state<=S_IDLE;
		endcase
end 

always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		hex_data<=24'h0; 
	else 
		case(state)
		S_IDLE:hex_data<=24'h0; 
		S_TIME:hex_data<={cnt_h_bcd1,cnt_h_bcd2,cnt_min_bcd1,cnt_min_bcd2,cnt_s_bcd1,cnt_s_bcd2}; 
		S_HOUR:
			if(flag_half)
				hex_data<={cnt_h_bcd1,cnt_h_bcd2,cnt_min_bcd1,cnt_min_bcd2,cnt_s_bcd1,cnt_s_bcd2}; 
			else
				hex_data<={8'hbb,cnt_min_bcd1,cnt_min_bcd2,cnt_s_bcd1,cnt_s_bcd2}; 
		S_MIN:
			if(flag_half)
				hex_data<={cnt_h_bcd1,cnt_h_bcd2,cnt_min_bcd1,cnt_min_bcd2,cnt_s_bcd1,cnt_s_bcd2}; 
			else
				hex_data<={cnt_h_bcd1,cnt_h_bcd2,8'hbb,cnt_s_bcd1,cnt_s_bcd2}; 
		S_CNT:hex_data<=24'h0; 
		S_CNT_RUN,S_CNT_STOP:hex_data<={c_min1_bcd1,c_min1_bcd2,c_s1_bcd1,c_s1_bcd2,c_100ms,c_10ms};		
		default:hex_data<=24'h0; 
		endcase
end 

parameter HALFS_MAX=25_000_000-1;//0.5s
parameter NS_MAX=50_000_000-1;//1s
parameter S_MAX=60-1;//1min
parameter MIN_MAX=60-1;//1h
parameter H_MAX=24-1;//1day

//生成修改时钟时的闪烁效果
//时钟分频,生成0.5s的时钟
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_ns_half<=0;
	else if(state==S_MIN||state==S_HOUR)
	begin
		if(cnt_ns_half==HALFS_MAX)
			cnt_ns_half<=0;
		else
			cnt_ns_half<=cnt_ns_half+1; 
	end
	else
		cnt_ns_half<=0;
end

always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		flag_half<=0;
	else if(cnt_ns_half==HALFS_MAX && (state==S_MIN||state==S_HOUR))
		flag_half<=~flag_half;

end
 //时钟分频,生成1s的时钟
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_ns<=0;
	else if(cnt_ns==NS_MAX)
		cnt_ns<=0;
	else
  		cnt_ns<=cnt_ns+1; 
end 

//秒计时
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_s<=0;
	else if(cnt_s==S_MAX && cnt_ns==NS_MAX)
		cnt_s<=0;
	else if(cnt_ns==NS_MAX)
  		cnt_s<=cnt_s+1;
end

wire flag_1_min=cnt_s==S_MAX && cnt_ns==NS_MAX;

//分钟计时
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_min<=57;
	else if(state==S_MIN)
	begin
		if(key_add && cnt_min<59)
			cnt_min<=cnt_min+1;
		else if(key_sub && cnt_min>0)
			cnt_min<=cnt_min-1;
	end	
	else if(cnt_min==MIN_MAX && flag_1_min)
			cnt_min<=0;
	else if(flag_1_min)
  			cnt_min<=cnt_min+1; 
end 


//小时计时
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_h<=5'd0;
	else if(state==S_HOUR)
	begin
		if(key_add && cnt_h<5'd23)
			cnt_h<=cnt_h+1;
		else if(key_sub && cnt_h>5'd0)
			cnt_h<=cnt_h-1;
	end
	else if(cnt_h==H_MAX && cnt_min==MIN_MAX && flag_1_min)
			cnt_h<=5'd0;
	else if(cnt_min==MIN_MAX && flag_1_min)
  			cnt_h<=cnt_h+1'b1;  

end 

//秒表
//毫秒数码管有2位,可以精确到10ms
// parameter MS_10MAX=5-1;//10ms
parameter MS_10MAX=500000-1;//10ms
//时钟分频,生成10ms的时钟
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_ns1<=20'd0;
	else if(state==S_CNT)
		cnt_ns1<=20'd0;
	else if(state==S_CNT_RUN || state==S_CNT_STOP)
	begin
		if(cnt_ns1==MS_10MAX)
			cnt_ns1<=20'd0;	
		else 
			cnt_ns1<=cnt_ns1+1; 
	end
	else
		cnt_ns1<=20'd0;	
end 

//10ms计时
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_10ms<=4'd0;
	else if(state==S_CNT)
		cnt_10ms<=5'd0;
	else if(state==S_CNT_RUN || state==S_CNT_STOP)
	begin
		if(cnt_10ms==4'd9 && cnt_ns1==MS_10MAX)
			cnt_10ms<=4'd0;
		else if(cnt_ns1==MS_10MAX)
  			cnt_10ms<=cnt_10ms+1'b1;   
	end
	else
		cnt_10ms<=4'd0;
end 

//100ms计时
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_100ms<=4'd0;
	else if(state==S_CNT)
		cnt_100ms<=4'd0;
	else if(state==S_CNT_RUN || state==S_CNT_STOP)
	begin
		if(cnt_100ms==4'd9 && cnt_10ms==4'd9 && cnt_ns1==MS_10MAX)
			cnt_100ms<=4'd0;
		else if(cnt_10ms==4'd9 && cnt_ns1==MS_10MAX)
  			cnt_100ms<=cnt_100ms+1'b1;   
	end
	else
		cnt_100ms<=4'd0;
end 


wire flag_1_s=(cnt_100ms==4'd9 && cnt_10ms==4'd9 && cnt_ns1==MS_10MAX);


//秒
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_s1<=6'd0;
	else if(state==S_CNT)
		cnt_s1<=4'd0;
	else if(state==S_CNT_RUN || state==S_CNT_STOP)
	begin
		if(flag_1_s && cnt_s1==6'd59)
			cnt_s1<=6'd0;
		else if(flag_1_s)
  			cnt_s1<=cnt_s1+1'b1;   
	end
	else
		cnt_s1<=6'd0;
end

//分
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		cnt_min1<=6'd0;
	else if(state==S_CNT)
		cnt_min1<=4'd0;
	else if(state==S_CNT_RUN || state==S_CNT_STOP)
	begin
		if(flag_1_s && cnt_min1==6'd59 && cnt_s1==6'd59)
			cnt_min1<=6'd0;
		else if(flag_1_s && cnt_s1==6'd59)
  			cnt_min1<=cnt_min1+1'b1;   
	end
	else
		cnt_min1<=6'd0;
end 


always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
		out_flag  <=1'd0;
	else if(state==S_CNT)
		out_flag  <=1'd0;
	else if((state==S_CNT_RUN || state==S_CNT_STOP) && key_add)
		out_flag<=~out_flag;
end

//输出
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
	begin
		m_c_10ms  <=4'd0;
		m_c_100ms <=4'd0;
		m_c_s1	  <=4'd0;
		m_c_min1  <=4'd0; 
	end
	else if(state==S_CNT_RUN && key_add)
	begin
		m_c_10ms  <=cnt_10ms  ;
		m_c_100ms <=cnt_100ms ;
		m_c_s1	  <=cnt_s1	    ;
		m_c_min1  <=cnt_min1	; 
	end
end 

//输出
always @(posedge clk or negedge rst_n)begin 
 	if(!rst_n)
	begin
		c_10ms  <=4'd0;
		c_100ms <=4'd0;
		c_s1	<=4'd0;
		c_min1	<=4'd0; 
	end
	else if(out_flag)
	begin
		c_10ms  <=m_c_10ms     ;
		c_100ms <=m_c_100ms   ;
		c_s1	<=m_c_s1	         ;
		c_min1  <=m_c_min1      	; 
	end
	else
	begin
		c_10ms  <=cnt_10ms  ;
		c_100ms <=cnt_100ms ;
		c_s1	<=cnt_s1	    ;
		c_min1	<=cnt_min1	; 
	end
end 


endmodule  

数码管驱动模块

module hex(
	clk,	//系统输入时钟
	rst_n,	//复位输入,低电平复位
	data_in,	//待显示数据
	point,	//待显示数据

	sel,
	seg
);
			
	//----------------模块输入端口----------------
	input  clk;          //系统输入时钟
	input  rst_n;
	input  [23:0]data_in;     //待显示数据
	input  [5:0]point;     //待显示数据

	//----------------模块输出端口----------------
	output [5:0]sel;
	output [7:0]seg;

	parameter CNT_MAX=50000;
	reg [15:0]cnt;
	reg flag;
	reg nisp;
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
		cnt<=16'd0;
	else if(cnt==CNT_MAX)
		cnt<=16'd0;
	else
		cnt<=cnt+1'b1;


	always@(posedge clk or negedge rst_n)
	if(!rst_n)
		flag<=1'd0;
	else if(cnt==CNT_MAX)
		flag<=1'd1;
	else
		flag<=1'd0;


reg [5:0]hex_sel;
reg [7:0]hex_seg;
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
		hex_sel<=4'h1;
	else if(flag)
		hex_sel<={hex_sel[4:0],hex_sel[5]};

reg [3:0]disp;
	always@(*)
	case(hex_sel)	
		6'b100000:begin nisp <=~point[5]; disp=data_in[23:20];end
		6'b010000:begin nisp <=~point[4]; disp=data_in[19:16];end
		6'b001000:begin nisp <=~point[3]; disp=data_in[15:12];end
		6'b000100:begin nisp <=~point[2]; disp=data_in[11:8];end
		6'b000010:begin nisp <=~point[1]; disp=data_in[7:4];end
		6'b000001:begin nisp <=~point[0]; disp=data_in[3:0];end
		default:begin nisp <=1'b1;disp=4'h0;end
	endcase


always @ (disp) begin
        case (disp)
            4'h0 : hex_seg = {nisp,7'b1000000}; //显示数字 0
            4'h1 : hex_seg = {nisp,7'b1111001}; //显示数字 1
            4'h2 : hex_seg = {nisp,7'b0100100}; //显示数字 2
            4'h3 : hex_seg = {nisp,7'b0110000}; //显示数字 3
            4'h4 : hex_seg = {nisp,7'b0011001}; //显示数字 4
            4'h5 : hex_seg = {nisp,7'b0010010}; //显示数字 5
            4'h6 : hex_seg = {nisp,7'b0000010}; //显示数字 6
            4'h7 : hex_seg = {nisp,7'b1111000}; //显示数字 7
            4'h8 : hex_seg = {nisp,7'b0000000}; //显示数字 8
            4'h9 : hex_seg = {nisp,7'b0010000}; //显示数字 9
				4'ha : hex_seg = {nisp,7'b0111111}; //显示-
				4'hb : hex_seg = {nisp,7'b1111111}; //不显示


			// 4'ha : hex_seg = {nisp,7'b0001000}; //显示数字 9
			// 4'hb : hex_seg = {nisp,7'b0000011}; //显示数字 9
			// 4'hc : hex_seg = {nisp,7'b1000110}; //显示数字 9
			// 4'hd : hex_seg = {nisp,7'b0100001}; //显示数字 9
			// 4'he : hex_seg = {nisp,7'b0000110}; //显示数字 9
			// 4'hf : hex_seg = {nisp,7'b0001110}; //显示数字 9
            // 4'hb : seg = 8'b10111111;           //显示负号(-)
            default:hex_seg = {nisp,7'b1000000};
        endcase
    end

	assign sel=~hex_sel;
	assign seg=hex_seg;

		
endmodule 

按键消抖模块

//--消抖模块
module xiaodou(
			input clk,//系统时钟输入
			input rst_n,//系统复位输入
			input key1,//外部按键输入
			output reg key_out1//消抖后的波形输出
	);
 
 ///
	reg [31:0] cnt1;
	parameter CNT_MAX=32'd2000000;

	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			cnt1 <= 0;
		else
			begin
				if(key1)                  //--当按键为1,即高电平的时候,说明没有按键按下(硬件特性),把计数寄存器清零,geo1的按键按下去时高电平,平时为低电平,因此输入时需要取反
					cnt1 <=0;
				else if(cnt1==CNT_MAX)//--如果上述条件不满足,即按键为低电平,说明有按键按下,此时我们开始计数,
					cnt1 <=cnt1;         //--因为毛刺的存在,按键低电平状态必须保持一段时间才能视为有效按下,几十毫秒是个可以接受的值
				else                     //--系统时钟是100MHz,即10ns一周期,则2000000*10ns=20000000ns=20ms
					cnt1 <=cnt1+1;       //--此段进程的目的就是,按键过程中,如果存在毛刺,则把计数寄存器清零,直到按键电平稳定为低,
			end                          //--有效计数时间能达到ms级别,我们认为按键有效
	end 

	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			key_out1 <= 1'b0;
		else
			begin
				if(cnt1==CNT_MAX-1)//--接上面的进程,按键电平稳定,计数时间能达到50ms的时候,我们产生按键脉冲,用于后续程序。
					key_out1 <= 1'b1;
				else
					key_out1 <= 1'b0;
			end
	end 
 

endmodule

演示视频

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值