1. 程式人生 > >FPGA-13-籃球計分計時器的設計

FPGA-13-籃球計分計時器的設計

這次的任務相對上次來說程式碼書寫的更為規範和簡潔

任務一、籃球計分器 功能:按照籃球賽賽制進行設計。須具有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;
	//數碼管特殊狀態閃爍計數器模組
	
[email protected]
(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倒計時
[email protected]
(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 //計分和計時顯示切換 [email protected](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 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;
	[email protected] (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)
	[email protected](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)
	[email protected](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
	//計數器模組高位 秒計時
	[email protected](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
	//計數器模組低位 秒計時
	[email protected](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);
	
	//計數器模組高位 分鐘計時
	[email protected](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
	//計數器模組低位 分鐘計時
	[email protected](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
	//計數器模組高位 秒計時
	[email protected](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
	//計數器模組低位 秒計時
	[email protected](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;
	[email protected](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;
	[email protected](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;
	//定時採取按鍵值
	[email protected](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;
	[email protected](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指示模組
	[email protected](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;
	[email protected](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;
	[email protected](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        ;//延時計數器計數位
	
	//延時計數器模組
	[email protected] (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