游戏规则:
用8个发光二极管排成一条直线,两边代表双方的位置。其中一个亮光二极管指示球的当前位置。
点依次发光二极管从上到下当点亮二极管运动到最后一个,参赛者按下按钮开关位于自己一侧,若击中使球向相反的方向移动,如果没有击中,对方必须1分,一方得分时,蜂鸣器鸣叫。
甲双方用两位数码管计分数码管显示了胜利统计 ,每计满11分为一局,并统计双方的胜局数。
甲乙方各设置发光二极管,表示有发球权5发球权自动交换。
功能模块设计
分频模块
//分频模块 module divide(clk,rst_n,clkout ); input clk,rst_n; output clkout; //parameter是verilog里常数语句 parameter WIDTH = 32; //计数器的位数,计数的最大值是 2**WIDTH-1 parameter N = 1000000; ///分频系数,请确保 N < 2**WIDTH-1.否则计数会溢出 reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p上升沿触发时的计数器,cnt_n为下降沿触发时的计数器 reg clk_p,clk_n; //clk_p上升沿触发时分频时钟,clk_n下降沿触发时分频时钟 //上升沿触发时计数器的控制 always @ (posedge clk or negedge rst_n ) //posedge和negedge是verilog表示信号上升和下降 //当clk上升或上升rst_n变低时执行一次always里的语句 begin if(!rst_n) cnt_p<=0; else if (cnt_p==(N-1)) cnt_p<=0; else cnt_p<=cnt_p 1; ///计数器一直在计数,当计数到达时N-1时清零,这是一个模N计数器 end ///上升沿触发的分频时钟输出,如果N是奇数,时钟占空比不是50%;如果N是偶数,时钟占空比为50% always @ (posedge clk or negedge rst_n) begin if(!rst_n) clk_p<=0; else if (cnt_p<(N>>1)) //N>>一是右移一位,除以2相当于去除余数 clk_p<=0; else clk_p<=1; ///分频时钟的正周期比负周期多一个clk时钟 end ///下降沿触发时计数器的控制 always @ (negedge clk or negedge rst_n) begin if(!rst_n) cnt_n<=0; else if (cnt_n==(N-1)) cnt_n<=0; else cnt_n<=cnt_n 1; end //输出沿触发的分频时钟,和clk_p相差半小时钟 always @ (negedge clk) begin if(!rst_n) clk_n<=0; else if (cnt_n<(N>>1)) clk_n<=0; else clk_n<=1; ///分频时钟的正周期比负周期多一个clk时钟 end assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; //条件判断表达式 //当N=1时,直接输出clk //当N为偶数,即N的最低位为0,N(0)=0,输出clk_p //当N为奇数,即N的最低位为1,N(0)=1,输出clk_p&clk_n。正周期多,所以是相和 endmodule
发球接球和评分模块
always @(posedge clk12hz or negedge rst ) begin if(!rst) begin win_a<=4'b0; win_b<=4'b0; led8s<=9'b000000000; state<=s0; led8s2<=2'b01; led8s3<=2'b00; end else begin case(state) s7: begin if(!k_a) state<=s1; ///甲发球; else if(!k_b) state<=s四、/乙发球; else if(speaker) speaker<=1'b0; else speaker<=1'b0; end s0: begin led8s<=9'b000000000; score_a<=0; score_b<=0; led8s2<=2'b01;//给甲乙双方分数复位; if(!k_a) begin speaker<=1'b0;//因为按钮k_a蜂鸣器鸣叫是为了保持高电位‘1’,可以放手; state<=s7; end else if(!k_b) begin speaker<=1'b0; state<=s7; end else state<=s0; end s1: begin if(led8s==9'b000000000) led8s<=9'b一万万;//点亮的灯出现在最右边,即甲方发球; state<=s2; if(speaker) speaker<=1'b0;///关闭刚刚鸣叫的蜂鸣器; end s2: begin f(cnt1>=N1)
begin
cnt1<=0;
if(led8s==9'b000000010)
begin
led8s <= {led8s[0],led8s[8:1]};
state<=s3;//进入判断乙方接球的状态;
end
else
begin
led8s <= {led8s[0],led8s[8:1]};
state<=s2;
end
end
else
cnt1<=cnt1+1;
end
s3: begin
if(!k_b)
begin
state<=s4;//乙方接球成功,并进入乙方发球的s4状态;
led8s<=9'b000000000;
end
else
begin
score_a<=score_a+1'b1;
speaker<=1'b1;
led8s3<=2'b10;
state<=s8;//乙方接球不成功,则甲方加一分,并进入甲方发球的s7状态,蜂鸣器鸣叫;
end
end
s4: begin
if(led8s==9'b000000000)
led8s<=9'b000000001;//点亮的灯出现在最左边,即乙方发球;
state<=s5;
if(speaker)
speaker<=1'b0;//将刚才鸣叫的蜂鸣器关闭;
end
s5: begin
if(cnt1>=N1)
begin
cnt1<=0;
if(led8s==9'b010000000)
begin
led8s <= {led8s[7:0],led8s[8]};
state<=s6;//进入判断甲方接球的状态;
end
else
begin
led8s <= {led8s[7:0],led8s[8]};
state<=s5;
end
end
else
cnt1<=cnt1+1;
end
s6: begin
if(!k_a)
begin
state<=s1;//甲方接球成功,并进入甲方发球的s7状态;
led8s<=9'b000000000;
end
else
begin
score_b<=score_b+1'b1;
speaker<=1'b1;
led8s3<=2'b01;
state<=s8;//甲方接球不成功,则乙方加一分,并进入乙方发球的s7状态,蜂鸣器鸣叫;
end
end
胜局统计和发球权判决模块
s8:begin
led8s<=9'b000000000;
fp<=score_a+score_b;
if(score_a==4'b1011)
begin
score_a<=0;
score_b<=0;//如果任一方得11分,一局结束,计分清零;
win_a<=win_a+1'b1;
state<=s7;
end
else if(score_b==4'b1011)
begin
score_a<=0;
score_b<=0;//如果任一方得11分,一局结束,计分清零;
win_b<=win_b+1'b1;
state<=s7;
end
else
if(fp==4||fp==9||fp==14||fp==19)
led8s2<=~led8s2;
state<=s7;
end
default:
begin
win_a<=4'b0;
win_b<=4'b0;
state<=s0;
end
endcase
end
分数显示模块
//----------甲乙双方的分数各用2个数码管显示-----------------------------------------------------------------
end
always @ (posedge clk or negedge rst)
begin
if(!rst)
begin
i1<=0;
end
else
begin
if(i1==3'b111)
i1<=0;
i1<=i1+3'b001 ;
end
end
always @ (posedge clk or negedge rst)
begin
if(!rst)
begin
seg1<=4'b0;
seg2<=4'b0;
end
else
begin
case(i1)
3'b000:
begin
seg1<=4'b1011;
seg2<=4'b1111;
j1<=score_b%(4'b1010);
end
3'b001:
begin
seg1<=4'b0111;
seg2<=4'b1111;
j1<=score_b/(4'b1010);
end
3'b011:
begin
seg1<=4'b1110;
seg2<=4'b1111;
j1<=win_b%(4'b1010);
end
3'b100:
begin
seg1<=4'b1111;
seg2<=4'b1110;
j1<=score_a%(4'b1010);
end
3'b101:
begin
seg1<=4'b1111;
seg2<=4'b1101;
j1<=score_a/(4'b1010);
end
3'b111:
begin
seg1<=4'b1111;
seg2<=4'b0111;
j1<=win_a%(4'b1010);
end
default:;
endcase
end
end
数码管显示模块
always @ (j1)
begin
case(j1)
8'b0000: begin
led7s1<=7'b0111111;//数码管显示0分;
end
8'b0001: begin
led7s1<=7'b0000110;//数码管显示1分;
end
8'b0010: begin
led7s1<=7'b1011011;//数码管显示2分;
end
8'b0011: begin
led7s1<=7'b1001111;//数码管显示3分;
end
8'b0100: begin
led7s1<=7'b1100110;//数码管显示4分;
end
8'b0101: begin
led7s1<=7'b1101101;//数码管显示5分;
end
8'b0110: begin
led7s1<=7'b1111101;//数码管显示6分;
end
8'b0111: begin
led7s1<=7'b0000111;//数码管显示7分;
end
8'b1000: begin
led7s1<=7'b1111111;//数码管显示8分;
end
8'b1001: begin
led7s1<=7'b1101111;//数码管显示9分;
end
default: begin
led7s1<=7'b0111111;//数码管显示0分;
end
endcase
end
endmodule