FPGA-篮球计分计时器的设计

这次的任务相对上次来说代码书写的更为规范和简洁

任务一、篮球计分器
功能:按照篮球赛赛制进行设计。须具有24秒倒计时功能,十二分钟计时功能,暂停功能,进球计分功能(1分,2分,3分)等。可再自由发挥。
要求:比分与计时须在数码管实时显示,显示状态可通过按键或者拨码开关切换,计分可通过按键进行设计(不限制)。

设计:

sw1  暂停

sw2  24秒倒计时

sw3  显示计时或者得分

key0 1分

key1 2分

key2 3分

key4计分切换

顶层模块:

module top(ext_clk_25m,ext_rst_n,
           switch1,switch2,switch3,
		   key_left,key_entr,key_righ,key_down,
		   dtube_cs_n,dtube_data,led
    );
	input         ext_clk_25m     ;//输入时钟
	input         ext_rst_n       ;//复位信号
	input         switch1         ;//暂停开关
	input         switch2         ;//24s使能开关
	input         switch3         ;//显示切换位
	input         key_left        ;//1分
	input         key_entr        ;//2分
	input         key_righ        ;//3分
	input         key_down        ;//切换记分
	
	output  [3:0] dtube_cs_n      ;//位选数据位
	output  [6:0] dtube_data      ;//段选数据位
	output  [3:0] led             ;	
	
	wire          clk             ;//中间变量
	wire   [15:0] times_24s       ;
	wire   [15:0] times_12m       ;
	wire   [15:0] times_sore      ;
	wire          en_cnt          ;
	wire          en_seg          ;
	wire          en_24s          ;
	wire          en_sor          ;
	//分频25MHZ变为1HZ
	div d1(
	.ext_clk_25m(ext_clk_25m),
	.ext_rst_n(ext_rst_n),
	.mclk(clk)
    );
	//控制电路
	control con1(
	.ext_clk_25m(ext_clk_25m),
	.ext_rst_n(ext_rst_n),
	.switch1(switch1),
	.switch2(switch2),
	.switch3(switch3),
	.en_cnt(en_cnt),
	.en_seg(en_seg),
	.en_24s(en_24s),
	.en_sore(en_sor)
    );
	//计分模块
	soring so1(
	.ext_clk_25m(ext_clk_25m),
	.ext_rst_n(ext_rst_n),
	.key_down(key_down),
	.key_left(key_left),
	.key_entr(key_entr),
	.key_righ(key_righ),
	.en_sore(en_sor),
	.sore(times_sore),
	.led(led[3:2])
    );
	//12分钟倒计时模块
	counter_12min c1(
	.ext_clk_25m(ext_clk_25m),
	.mclk(clk),
	.ext_rst_n(ext_rst_n),
	.en_24s(en_24s),
	.en_cnt(en_cnt),
	.times_12m(times_12m),
	.led(led[0])
    );
	//24分钟倒计时模块
	counter_24 c2(
	.ext_clk_25m(ext_clk_25m),
	.mclk(clk),
	.ext_rst_n(ext_rst_n),
	.en_24s(en_24s),
	.en_cnt(en_cnt),
	.times_24s(times_24s),
	.led(led[1])
    );
	//数码管显示模块
	seg s1(
	.ext_clk_25m(ext_clk_25m),
	.ext_rst_n(ext_rst_n),
	.times_24s(times_24s),
	.times_12m(times_12m),
	.times_sore(times_sore),
	.en_24s(en_24s),
	.en_seg(en_seg),
	.en_sore(en_sor),
	.dtube_cs_n(dtube_cs_n),
	.dtube_data(dtube_data)	
	);
	
module control(ext_clk_25m,ext_rst_n,switch1,switch2,switch3,en_cnt,en_seg,en_24s,en_sore
    );
	input       ext_clk_25m;		//输入时钟
	input       ext_rst_n  ;		//复位信号
	input       switch1    ;		//暂停开关
	input       switch2    ;        //24s使能开关
	input       switch3    ;        //显示切换位
	output  reg en_cnt     ;		//暂停计数使能位
	output  reg en_seg     ;        //数码管显示使能位
	output  reg en_24s     ;        //24s使能位
	output  reg en_sore    ;        //计分使能位
	
	reg  [24:0] cnt        ;        //存放计数器的值
	parameter TIME = 25'd2500_0000;
	//数码管特殊状态闪烁计数器模块
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			cnt <=25'd0;
		end
		else if(cnt ==TIME-1'b1)begin
			cnt <=1'b0;
		end
		else begin
			cnt <=cnt + 1'b1;
		end
	end
	//数码管闪烁模块
	always @(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			en_seg<=1'b0;
		end
		else if(switch1==1'b0)begin
			if(cnt<(TIME/2-1'b1))begin
				en_seg<=1'b1;
			end
			else begin
				en_seg<=1'b0;
			end
		end
		else begin
			en_seg<=1'b0;
		end
	end
	//停止计数器计时模块
	always @(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			en_cnt<=1'b0;
		end
		else if(switch1==1'b0)begin
			en_cnt<=1'b1;
		end
		else begin
			en_cnt<=1'b0;
		end
	end
	//开启24s倒计时
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			en_24s <=1'b0;
		end
		else if(switch2==1'b0)begin
			en_24s <=1'b1;
		end
		else begin
			en_24s <=1'b0;
		end
	end
	//计分和计时显示切换
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			en_sore <=1'b0;
		end
		else if(switch3==1'b0)begin
			en_sore <=1'b1;
		end
		else begin
			en_sore <=1'b0;
		end
	end
endmodule
module div(ext_clk_25m,ext_rst_n,mclk
    );
	input           ext_clk_25m    ;//输入时钟
	input           ext_rst_n      ;//复位端口
	output      reg mclk           ;//输出1Hz
	
	reg      [23:0] cnt            ;//存放计数器的值
	parameter TIME=   24'd1250_0000;//时钟25MHz
//分频模块,使得输入时钟为25MHz输出时钟为1Hz
	always@ (posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			mclk <=1'b0;
			cnt <=24'd0;
		end
		else if(cnt ==TIME-1'b1)begin
			mclk <=~mclk;
			cnt <=1'b0;
		end
		else begin
			cnt <=cnt + 1'b1;
		end
	end
endmodule
module counter_24(ext_clk_25m,mclk,ext_rst_n,en_24s,en_cnt,times_24s,led
    );
	input             ext_clk_25m       ;//系统时钟
	input             mclk              ;//时钟信号
	input             ext_rst_n         ;//复位信号
	input             en_24s            ;//24s使能位
	input             en_cnt            ;//计数器停止使能位
	output reg [15:0] times_24s         ;
	output            led               ;//led指示状态
	
	assign led =(times_24s==16'h0000);

	reg      [24:0] cnt            ;//存放计数器的值
	parameter TIME=   25'd2500_0000;
	always@ (posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			cnt <=25'd0;
		end
		else if(cnt ==TIME-1'b1)begin
			cnt <=1'b0;
		end
		else begin
			cnt <=cnt + 1'b1;
		end
	end
	//计数器模块高位 秒计时(99)
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			times_24s[7:4] <=4'h9;		
		end
		else if(en_24s==1'b0)begin
			times_24s[7:4] <=4'h9;
		end
		else if(en_cnt==1'b1)begin
			times_24s[7:4] <=times_24s[7:4];
		end
		else if(cnt%25'd25_0000==0)begin
			if({times_24s[7:4],times_24s[3:0]}==8'h00)begin
				if({times_24s[15:12],times_24s[11:8]}==8'h00)begin
					times_24s[7:4] <=4'h0; 
				end
				else begin
					times_24s[7:4] <=4'h9;
				end
			end
			else if(times_24s[3:0]==4'h0)begin
				times_24s[7:4] <=times_24s[7:4]-1'b1;
			end
			else begin
				times_24s[7:4] <=times_24s[7:4];
			end
		end
		else begin
			times_24s[7:4] <=times_24s[7:4];
		end	
	end
	//计数器模块低位 秒计时(99)
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			times_24s[3:0] <=4'h9;
		end
		else if(en_24s==1'b0)begin
			times_24s[3:0] <=4'h9;
		end
		else if(en_cnt==1'b1)begin
			times_24s[3:0] <=times_24s[3:0];
		end
		else if(cnt%25'd25_0000==0)begin
			if({times_24s[7:4],times_24s[3:0]}==8'h00) begin
				if({times_24s[15:12],times_24s[11:8]}==8'h00)begin
					times_24s[3:0] <=4'h0; 
				end
				else begin
					times_24s[3:0] <=4'h9;
				end
			end
			else if(times_24s[3:0]==4'h0)begin
				times_24s[3:0] <=4'h9;
			end
			else begin
				times_24s[3:0] <=times_24s[3:0]-1'b1;
			end
		end
		else begin
			times_24s[3:0] <=times_24s[3:0];
		end
	end
	//计数器模块高位 秒计时
	always@(posedge mclk or negedge ext_rst_n)
	begin
		if(!ext_rst_n)begin
			times_24s[15:12] <=4'h2;		
		end
		else if(en_24s==1'b0)begin
			times_24s[15:12] <=4'h2;
		end
		else if(en_cnt==1'b1)begin
			times_24s[15:12] <=times_24s[15:12];
		end
		else if({times_24s[15:12],times_24s[11:8]}==8'h00)begin
			times_24s[15:12] <=4'h0; 
		end
		else if(times_24s[11:8]==4'h0)begin
			times_24s[15:12] <=times_24s[15:12]-1'b1;
		end
		else begin
			times_24s[15:12] <=times_24s[15:12];
		end
	end
	//计数器模块低位 秒计时
	always@(posedge mclk or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			times_24s[11:8] <=4'h3;
		end
		else if(en_24s==1'b0)begin
			times_24s[11:8] <=4'h3;
		end
		else if(en_cnt==1'b1)begin
			times_24s[11:8] <=times_24s[11:8];
		end
		else if({times_24s[15:12],times_24s[11:8]}==8'h00) begin
			times_24s[11:8] <=4'h0;
		end
		else if(times_24s[11:8]==4'h0)begin
			times_24s[11:8] <=4'h9;
		end
		else begin
			times_24s[11:8] <=times_24s[11:8]-1'b1;
		end
	end
endmodule
module counter_12min(ext_clk_25m,mclk,ext_rst_n,en_24s,en_cnt,times_12m,led
    );
	input           ext_clk_25m       ;//系统时钟
	input           mclk              ;//时钟信号
	input           ext_rst_n         ;//复位信号
	input           en_24s            ;//24s使能位
	input           en_cnt            ;//计数器停止使能位
	output reg[15:0]times_12m         ;//15-12分高位 11-8 分低位 7-4秒高位 3-0秒低位
	output          led               ;//led指示状态
	
	assign led =(times_12m==16'h0000);
	
	//计数器模块高位 分钟计时
	always@(posedge mclk or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			times_12m[15:12] <=4'h1;		
		end
		else if(en_24s==1'b1)begin
			times_12m[15:12] <=4'h1;
		end
		else if(en_cnt==1'b1)begin
			times_12m[15:12] <=times_12m[15:12];
		end
		else if({times_12m[15:12],times_12m[11:8]}==8'h00)begin
			times_12m[15:12] <=4'h0; 
		end
		else if({times_12m[7:4],times_12m[3:0]}==8'h00) begin
			if(times_12m[11:8]==4'h0)begin
				times_12m[15:12] <=times_12m[15:12]-1'b1;
			end
			else begin
				times_12m[15:12] <=times_12m[15:12];
			end
		end
		else begin
			times_12m[15:12] <=times_12m[15:12];
		end
	end
	//计数器模块低位 分钟计时
	always@(posedge mclk or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			times_12m[11:8] <=4'h1;    
		end
		else if(en_24s==1'b1)begin
			times_12m[11:8] <=4'h1;
		end
		else if(en_cnt==1'b1)begin
			times_12m[11:8] <=times_12m[11:8];
		end
		else if({times_12m[15:12],times_12m[11:8]}==8'h00)begin
			times_12m[11:8] <=4'h0; 
		end
		else if({times_12m[7:4],times_12m[3:0]}==8'h00) begin
			if(times_12m[11:8]==4'h0)begin
				times_12m[11:8] <=4'h9;
			end
			else begin 
				times_12m[11:8] <=times_12m[11:8]-1'b1;
			end
		end
		else begin
			times_12m[11:8] <=times_12m[11:8];
		end
	end
	//计数器模块高位 秒计时
	always@(posedge mclk or negedge ext_rst_n)
	begin
		if(!ext_rst_n)begin
			times_12m[7:4] <=4'h5;	
		end
		else if(en_24s==1'b1)begin
			times_12m[7:4] <=4'h5;
		end
		else if(en_cnt==1'b1)begin
			times_12m[7:4] <=times_12m[7:4];
		end
		else if({times_12m[7:4],times_12m[3:0]}==8'h00)begin
			if({times_12m[15:12],times_12m[11:8]}==8'h00)begin
				times_12m[7:4] <=4'h0;
			end
			else begin
				times_12m[7:4] <=4'h5;
			end
		end
		else if(times_12m[3:0]==4'h0)begin
			times_12m[7:4] <=times_12m[7:4]-1'b1;
		end
		else begin
			times_12m[7:4] <=times_12m[7:4];
		end
	end
	//计数器模块低位 秒计时
	always@(posedge mclk or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			times_12m[3:0] <=4'h9;    
		end
		else if(en_24s==1'b1)begin
			times_12m[3:0] <=4'h9;
		end
		else if(en_cnt==1'b1)begin
			times_12m[3:0] <=times_12m[3:0];
		end
		else if({times_12m[7:4],times_12m[3:0]}==8'h00) begin
			if({times_12m[15:12],times_12m[11:8]}==8'h00)begin
				times_12m[3:0] <=4'h0;
			end
			else begin
				times_12m[3:0] <=4'h9;
			end
		end
		else if(times_12m[3:0]==4'h0)begin
			times_12m[3:0] <=4'h9;
		end
		else begin
			times_12m[3:0] <=times_12m[3:0]-1'b1;
		end
	end
	
endmodule
module soring(ext_clk_25m,ext_rst_n,key_down,key_left,key_entr,key_righ,en_sore,sore,led
    );
	input             ext_clk_25m   ;//时钟信号
	input             ext_rst_n     ;//复位信号
	input             key_down      ;//切换记分
	input             key_left      ;//1分
	input             key_entr      ;//2分
	input             key_righ      ;//3分
	input             en_sore       ;//积分使能位
	output     [15:0] sore          ;//15-8 7-0分别为两个队的分数
	output reg  [1:0] led           ;//
	
	//按键抖动判断逻辑
	wire key;  //所有的按键相与的结果,用于按键触发判断
	reg[3:0]keyr ; //按键值key的缓冲寄存器
	assign key =key_down & key_entr&key_left&key_righ;
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			keyr <=4'b1111;
		end
		else begin
			keyr <={keyr[2:0],key};
		end
	end
	wire key_neg;
	wire key_pos;
	assign key_neg=~keyr[2] &keyr [3];//有按键被按下
	assign key_pos=keyr[2] &~keyr [3];//有按键被释放
	//定时器计数逻辑,用于对按键的消抖的判断
	reg [19:0] cnt;
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			cnt <=20'd0;
		end
		else if(key_pos||key_neg)begin
			cnt <=20'd0;
		end
		else if(cnt <20'd999_999)begin
			cnt <= cnt +1'b1;
		end
		else begin
			cnt <=20'd0;
		end
	end
	reg[3:0]key_value_c;
	reg[3:0]key_value_n;
	//定时采取按键值
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin
			key_value_c <=4'b1111;
			key_value_n <=4'b1111;
		end
		else begin
			if(cnt ==20'd999_999)begin
				key_value_c <={key_down,key_righ,key_entr,key_left};
			end
			else begin
				key_value_n <=key_value_c;
			end
		end
	end
	wire [3:0]key_press =key_value_n & ~key_value_c;
	//计分标志模块
	reg sore_f;
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			sore_f<=1'b0;
		end
		else if(en_sore==1'b0)begin
			sore_f<=1'b0;
		end
		else if(key_press[3]==1'b1)begin
			sore_f<=~sore_f;
		end
		else begin
			sore_f<=sore_f;
		end
	end
	//led指示模块
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			led<=2'b11;
		end
		else if(en_sore==1'b0)begin
			led<=led;
		end
		else if(sore_f==1'b0)begin
			led<=2'b10;
		end
		else begin
			led<=2'b01;
		end
	end
	//第一队比分
	reg [7:0] sore_1;
	assign sore[15:12]=sore_1/10;
	assign sore[11:8]=sore_1%10;
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			sore_1<=8'h00;
		end
		else if(en_sore==1'b0)begin
			sore_1<=sore_1;
		end
		else if(sore_1==8'd99)begin
			sore_1<=8'h00;
		end
		else if(key_press[0]==1'b1&&sore_f==1'b0)begin
			sore_1<=sore_1+1'b1;
		end
		else if(key_press[1]==1'b1&&sore_f==1'b0)begin
			sore_1<=sore_1+2'b10;
		end
		else if(key_press[2]==1'b1&&sore_f==1'b0)begin
			sore_1<=sore_1+2'b11;
		end
		else begin
			sore_1<=sore_1;
		end
	end
	//第二队比分
	reg [7:0] sore_2;
	assign sore[7:4]=sore_2/10;
	assign sore[3:0]=sore_2%10;
	always@(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(ext_rst_n==1'b0)begin
			sore_2<=8'h00;
		end
		else if(en_sore==1'b0)begin
			sore_2<=sore_2;
		end
		else if(sore_2==8'd99)begin
			sore_2<=8'h00;
		end
		else if(key_press[0]==1'b1&&sore_f==1'b1)begin
			sore_2<=sore_2+1'b1;
		end
		else if(key_press[1]==1'b1&&sore_f==1'b1)begin
			sore_2<=sore_2+2'b10;
		end
		else if(key_press[2]==1'b1&&sore_f==1'b1)begin
			sore_2<=sore_2+2'b11;
		end
		else begin
			sore_2<=sore_2;
		end
	end
endmodule
module seg( ext_clk_25m,ext_rst_n,
			times_24s,times_12m,times_sore,
			en_24s,en_seg,en_sore,
			dtube_cs_n,dtube_data	
		);
	input           ext_clk_25m    ;//时钟信号25MHz
	input           ext_rst_n      ;//复位信号
	input    [15:0] times_24s      ;//24秒倒计时显示位
	input    [15:0] times_12m      ;//12分倒计时显示位
	input    [15:0] times_sore     ;//分数显示数据
	input           en_24s         ;//24秒倒计时使能端
	input           en_seg         ;//显示使能端
	input           en_sore       ;//积分使能端
	output   [ 3:0] dtube_cs_n     ;//段选数据位
	output   [ 6:0] dtube_data     ;//位选数据位
	

	reg      [ 3:0] dtube_cs_n     ;
	reg      [ 6:0] dtube_data     ;
	reg      [ 3:0] display_num    ;//当前显示数据
	reg      [16:0] div_cnt        ;//延时计数器计数位
	
	//延时计数器模块
	always@ (posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n) begin
			div_cnt <= 8'd0;
		end
		else if(div_cnt==17'd80000)begin
			div_cnt <= 8'd0;		
		end
		else begin
			div_cnt <= div_cnt+1'b1;
		end
	end
	
	
	//显示当前的数据模块
	always @(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n)begin 
			display_num <= 4'h0;
		end
		else if(div_cnt < 17'd20000)begin
			if(en_24s==1'b1)begin
				display_num <= times_24s[3:0];
			end
			else if(en_sore==1'b1)begin
				display_num <= times_sore[3:0];
			end
			else begin
				display_num <= times_12m[3:0];
			end
		end
		else if((div_cnt>17'd20000)&(div_cnt <17'd40000))begin
			if(en_24s==1'b1)begin
				display_num <= times_24s[7:4];
			end
			else if(en_sore==1'b1)begin
				display_num <= times_sore[7:4];
			end
			else begin
				display_num <= times_12m[7:4];
			end
		end
		else if((div_cnt>17'd40000)&(div_cnt < 17'd60000))begin
			if(en_24s==1'b1)begin
				display_num <= times_24s[11:8];
			end
			else if(en_sore==1'b1)begin
				display_num <= times_sore[11:8];
			end
			else begin
				display_num <= times_12m[11:8];
			end
		end
		else begin
			if(en_24s==1'b1)begin
				display_num <= times_24s[15:12];
			end
			else if(en_sore==1'b1)begin
				display_num <= times_sore[15:12];
			end
			else begin
				display_num <= times_12m[15:12];
			end
		end
	end
		
	//段选数据译码模块(共阴数码管)
	always @(*)begin
		if(!ext_rst_n)begin 
			dtube_data <= 8'h00;
		end
		else begin
			case(display_num) 
				4'h0: dtube_data <= 8'h3f;
				4'h1: dtube_data <= 8'h06;
				4'h2: dtube_data <= 8'h5b;
				4'h3: dtube_data <= 8'h4f;
				4'h4: dtube_data <= 8'h66;
				4'h5: dtube_data <= 8'h6d;
				4'h6: dtube_data <= 8'h7d;
				4'h7: dtube_data <= 8'h07;
				4'h8: dtube_data <= 8'h7f;
				4'h9: dtube_data <= 8'h6f;
				default:dtube_data <= 8'h00;
			endcase
		end
	end
	//位选选译模块
	always @(posedge ext_clk_25m or negedge ext_rst_n)begin
		if(!ext_rst_n) begin
			dtube_cs_n <=  4'b1111;
		end
		else if(en_seg==1'b1)begin
			dtube_cs_n <=  4'b1111;
		end
		else if(div_cnt <= 17'd20000)begin
			dtube_cs_n <= 4'b1110;
        end
		else if((div_cnt>17'd20000)&(div_cnt <=17'd40000))begin
			dtube_cs_n <= 4'b1101;
        end 
		else if((div_cnt>17'd40000)&(div_cnt <=17'd60000))begin
			dtube_cs_n <= 4'b1011;
		end
		else if((div_cnt>17'd60000)&(div_cnt <=17'd80000))begin
			dtube_cs_n <=4'b0111;
		end
		else begin
			dtube_cs_n <=  4'b1111;
		end
	end
		
endmodule

 

你可能感兴趣的:(#,FPGA学习篇)