这次的任务相对上次来说代码书写的更为规范和简洁
任务一、篮球计分器
功能:按照篮球赛赛制进行设计。须具有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