数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏
设计目的
使用FPGA实验班设计一个数字逻辑系统,巩固数字逻辑电路的相关知识,锻炼熟练使用FPGA设计软件和硬件和独立完成项目设计的能力。
二、设计内容
2.1摘要
设计一个乒乓球游戏,实现游戏功能和计分功能。
通过开发板的按键实现左右球拍的击拍和游戏的复位;通过数码管显示游戏的比分;通过led显示乒乓球的运动轨迹。
2.2游戏规则
第一步:按下复位,led不亮,数码管显示比分00–00。
第二步:按下左球拍或者右球拍,发球,游戏开始,发球方向随机。
第三步:乒乓球在左半场/右半场并且靠近左侧/右侧的时候,左球拍/右球拍可以击球。如果在错误的时机击球或未成功接球,判负,对方加一分。
第四步:当有一方积得11分,游戏结束。再次开始游戏需要进行复位。
三、设计思路
3.2流程图
3.2顶层框图
3.3接口说明
名称 类型 封装管脚 说明
clk input PIN_AF14 时钟信号
rst_n input PIN_AA15 全局复位
key_left input PIN_Y16 左球拍
key_right input PIN_AA14 右球拍
Seven_segment output 数码管对应管脚 计分器
led output led对应管脚 运球轨迹
3.4分模块框图
四、代码实现
4.1顶层文件
module play_table_tennis (
input wire clk, // 50Mhz
input wire rst_n, // low valid
output wire [41:0] seven_segment, // low valid
output wire [9:0] led, // high valid
input wire key_left, // low valid
input wire key_right // low valid
);
wire flag_left;
wire flag_right;
wire [3:0] left_num;
wire [3:0] right_num;
key_processor key_processor_inst(
.clk (clk),
.rst_n (rst_n),
.key_left (key_left),
.key_right (key_right),
.flag_left (flag_left),
.flag_right (flag_right)
);
controller controller_inst(
.clk (clk),
.rst_n (rst_n),
.flag_left (flag_left),
.flag_right (flag_right),
.left_num (left_num),
.right_num (right_num),
.led (led)
);
seven_tube_drive seven_tube_drive_inst(
.clk (clk),
.rst_n (rst_n),
.left_num (left_num),
.right_num (right_num),
.seven_segment (seven_segment)
);
endmodule
4.2按键
module key_processor (
input wire clk,
input wire rst_n,
input wire key_left,
input wire key_right,
output wire flag_left,
output wire flag_right
);
key_filter key_filter_inst_left(
.clk (clk),
.rst_n (rst_n),
.key (key_left),
.flag (flag_left)
);
key_filter key_filter_inst_right(
.clk (clk),
.rst_n (rst_n),
.key (key_right),
.flag (flag_right)
);
endmodule
module key_filter (
input wire clk,
input wire rst_n,
input wire key,
output reg flag
);
parameter T = 500_000;
reg [18:0] cnt;
reg [2:0] state;
reg key_r;
reg key_rr;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
key_r <= 1'b1;
key_rr <= 1'b1;
end
else begin
key_r <= key;
key_rr <= key_r;
end
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
state <= 3'd0;
cnt <= 19'd0;
flag <= 1'b0;
end
else
case (state)
3'd0 : begin
state <= 3'd1;
cnt <= 19'd0;
flag <= 1'b0;
end
3'd1 : begin
if (key_rr == 1'b0)
state <= 3'd2;
else
state <= 3'd1;
end
3'd2 : begin
if (key_rr == 1'b1) begin
state <= 3'd1;
cnt <= 19'd0;
end
else
if (cnt < T - 1'b1)
cnt <= cnt + 1'b1;
else begin
cnt <= 19'd0;
state <= 3'd3;
flag <= 1'b1;
end
end
3'd3 : begin
flag <= 1'b0;
if (key_rr == 1'b1)
state <= 3'd4;
else
state <= 3'd3;
end
3'd4 : begin
if (key_rr == 1'b0) begin
state <= 3'd3;
cnt <= 19'd0;
end
else
if (cnt < T - 1'b1)
cnt <= cnt + 1'b1;
else begin
cnt <= 19'd0;
state <= 3'd0;
end
end
default : state <= 3'd0;
endcase
end
endmodule
4.3控制器
module controller (
input wire clk,
input wire rst_n,
input wire flag_left,
input wire flag_right,
output reg [3:0] left_num,
output reg [3:0] right_num,
output reg [9:0] led
);
parameter T = 50_000_000;
reg [25:0] cnt;
wire flag_t;
reg time_on;
reg init_dir;
reg dir; // 0 right 1 left
reg [3:0] state;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
cnt <= 26'd0;
else
if (time_on == 1'b0 || flag_left == 1'b1 || flag_right == 1'b1)
cnt <= 26'd0;
else
if (cnt < T - 1'b1)
cnt <= cnt + 1'b1;
else
cnt <= 26'd0;
end
assign flag_t = (cnt == T - 1'b1);
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
init_dir <= 1'b0;
else
init_dir <= ~init_dir;
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
state <= 4'd0;
dir <= 1'b0;
left_num <= 4'd0;
right_num <= 4'd0;
led <= 10'd0;
time_on <= 1'b0;
end
else
case (state)
4'd0 : begin
state <= 4'd1;
dir <= 1'b0;
left_num <= 4'd0;
right_num <= 4'd0;
led <= 10'd0;
time_on <= 1'b0;
end
4'd1 : begin
if (flag_left ==1'b1 || flag_right == 1'b1) begin
if (init_dir == 1'b1) begin
dir <= init_dir;
state <= 4'd6;
time_on <= 1'b1;
end
else begin
dir <= init_dir;
state <= 4'd7;
time_on <= 1'b1;
end
end
else
state <= 4'd1;
end
4'd2 : begin
led <= 10'b10000_00000;
if (flag_right == 1'b1)
state <= 4'd12;
else
if (flag_left == 1'b1)
if (dir == 1'b1) begin
dir <= ~dir;
state <= 4'd3;
end
else
state <= 4'd13;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd3;
else
state <= 4'd13;
else
state <= 4'd2;
end
4'd3 : begin
led <= 10'b01000_00000;
if (flag_right == 1'b1)
state <= 4'd12;
else
if (flag_left == 1'b1)
if (dir == 1'b1) begin
dir <= ~dir;
state <= 4'd4;
end
else
state <= 4'd13;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd4;
else
state <= 4'd2;
else
state <= 4'd3;
end
4'd4 : begin
led <= 10'b00100_00000;
if (flag_right == 1'b1)
state <= 4'd12;
else
if (flag_left == 1'b1)
if (dir == 1'b1) begin
dir <= ~dir;
state <= 4'd5;
end
else
state <= 4'd13;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd5;
else
state <= 4'd3;
else
state <= 4'd4;
end
4'd5 : begin
led <= 10'b00010_00000;
if (flag_right == 1'b1)
state <= 4'd12;
else
if (flag_left == 1'b1)
if (dir == 1'b1) begin
dir <= ~dir;
state <= 4'd6;
end
else
state <= 4'd13;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd6;
else
state <= 4'd4;
else
state <= 4'd5;
end
4'd6 : begin
led <= 10'b00001_00000;
if (flag_right == 1'b1)
state <= 4'd12;
else
if (flag_left == 1'b1)
if (dir == 1'b1) begin
dir <= ~dir;
state <= 4'd7;
end
else
state <= 4'd13;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd7;
else
state <= 4'd5;
else
state <= 4'd6;
end
4'd7 : begin
led <= 10'b00000_10000;
if (flag_left == 1'b1)
state <= 4'd13;
else
if (flag_right == 1'b1)
if (dir == 1'b0) begin
dir <= ~dir;
state <= 4'd6;
end
else
state <= 4'd12;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd8;
else
state <= 4'd6;
else
state <= 4'd7;
end
4'd8 : begin
led <= 10'b00000_01000;
if (flag_left == 1'b1)
state <= 4'd13;
else
if (flag_right == 1'b1)
if (dir == 1'b0) begin
dir <= ~dir;
state <= 4'd7;
end
else
state <= 4'd12;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd9;
else
state <= 4'd7;
else
state <= 4'd8;
end
4'd9 : begin
led <= 10'b00000_00100;
if (flag_left == 1'b1)
state <= 4'd13;
else
if (flag_right == 1'b1)
if (dir == 1'b0) begin
dir <= ~dir;
state <= 4'd8;
end
else
state <= 4'd12;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd10;
else
state <= 4'd8;
else
state <= 4'd9;
end
4'd10 : begin
led <= 10'b00000_00010;
if (flag_left == 1'b1)
state <= 4'd13;
else
if (flag_right == 1'b1)
if (dir == 1'b0) begin
dir <= ~dir;
state <= 4'd9;
end
else
state <= 4'd12;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd11;
else
state <= 4'd9;
else
state <= 4'd10;
end
4'd11 : begin
led <= 10'b00000_00001;
if (flag_left == 1'b1)
state <= 4'd13;
else
if (flag_right == 1'b1)
if (dir == 1'b0) begin
dir <= ~dir;
state <= 4'd10;
end
else
state <= 4'd12;
else
if (flag_t == 1'b1)
if (dir == 1'b0)
state <= 4'd12;
else
state <= 4'd10;
else
state <= 4'd11;
end
4'd12 : begin
led <= 10'd0;
time_on <= 1'b0;
if (left_num < 4'd10) begin
state <= 4'd1;
left_num <= left_num + 1'b1;
end
else begin
state <= 4'd14;
left_num <= left_num + 1'b1;
end
end
4'd13 : begin
led <= 10'd0;
time_on <= 1'b0;
if (right_num < 4'd10) begin
state <= 4'd1;
right_num <= right_num + 1'b1;
end
else begin
state <= 4'd14;
right_num <= right_num + 1'b1;
end
end
4'd14 : state <= 4'd14;
default : state <= 4'd0;
endcase
end
endmodule
4.4数码管显示
module seven_tube_drive (
input wire clk,
input wire rst_n,
input wire [3:0] left_num,
input wire [3:0] right_num,
output wire [41:0] seven_segment
);
wire [3:0] data_0;
wire [3:0] data_1;
wire [3:0] data_2;
wire [3:0] data_3;
wire [3:0] data_4;
wire [3:0] data_5;
show_data_sel show_data_sel_inst(
.clk (clk),
.rst_n (rst_n),
.left_num (left_num),
.right_num (right_num),
.data_0 (data_0),
.data_1 (data_1),
.data_2 (data_2),
.data_3 (data_3),
.data_4 (data_4),
.data_5 (data_5)
);
single_seven_tube_drive single_seven_tube_drive_inst0(
.clk (clk),
.rst_n (rst_n),
.data (data_0),
.seven_segment (seven_segment[6:0])
);
single_seven_tube_drive single_seven_tube_drive_inst1(
.clk (clk),
.rst_n (rst_n),
.data (data_1),
.seven_segment (seven_segment[13:7])
);
single_seven_tube_drive single_seven_tube_drive_inst2(
.clk (clk),
.rst_n (rst_n),
.data (data_2),
.seven_segment (seven_segment[20:14])
);
single_seven_tube_drive single_seven_tube_drive_inst3(
.clk (clk),
.rst_n (rst_n),
.data (data_3),
.seven_segment (seven_segment[27:21])
);
single_seven_tube_drive single_seven_tube_drive_inst4(
.clk (clk),
.rst_n (rst_n),
.data (data_4),
.seven_segment (seven_segment[34:28])
);
single_seven_tube_drive single_seven_tube_drive_inst5(
.clk (clk),
.rst_n (rst_n),
.data (data_5),
.seven_segment (seven_segment[41:35])
);
endmodule
module single_seven_tube_drive (
input wire clk,
input wire rst_n,
input wire [3:0] data,
output reg [6:0] seven_segment
);
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
seven_segment <= 7'h7f;
else
case (data)
4'd0 : seven_segment <= 7'b100_0000;
4'd1 : seven_segment <= 7'b111_1001;
4'd2 : seven_segment <= 7'b010_0100;
4'd3 : seven_segment <= 7'b011_0000;
4'd4 : seven_segment <= 7'b001_1001;
4'd5 : seven_segment <= 7'b001_0010;
4'd6 : seven_segment <= 7'b000_0010;
4'd7 : seven_segment <= 7'b111_1000;
4'd8 : seven_segment <= 7'b000_0000;
4'd9 : seven_segment <= 7'b001_0000;
4'd10 : seven_segment <= 7'b011_1111;
default : seven_segment <= 7'h7f;
endcase
end
endmodule
module show_data_sel (
input wire clk,
input wire rst_n,
input wire [3:0] left_num,
input wire [3:0] right_num,
output reg [3:0] data_0,
output reg [3:0] data_1,
output wire [3:0] data_2,
output wire [3:0] data_3,
output reg [3:0] data_4,
output reg [3:0] data_5
);
assign data_2 = 4'ha;
assign data_3 = 4'ha;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
data_0 <= 4'hb;
else
data_0 <= right_num%10;
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
data_1 <= 4'hb;
else
data_1 <= right_num/10;
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
data_4 <= 4'hb;
else
data_4 <= left_num%10;
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
data_5 <= 4'hb;
else
data_5 <= left_num/10;
end
endmodule
五、顶层仿真
5.1testbench代码
`timescale 1ns/1ps
module play_table_tennis_tb;
reg clk;
reg rst_n;
wire [41:0] seven_segment;
wire [9:0] led;
reg key_left;
reg key_right;
defparam play_table_tennis_inst.key_processor_inst.key_filter_inst_left.T = 10;
defparam play_table_tennis_inst.key_processor_inst.key_filter_inst_right.T = 10;
defparam play_table_tennis_inst.controller_inst.T = 100;
play_table_tennis play_table_tennis_inst(
clk, // 50Mhz
rst_n, // low valid
seven_segment, // low valid
led, // high valid
key_left, // low valid
key_right // low valid
);
initial clk = 1'b0;
always # 10 clk = ~clk;
initial begin
rst_n = 1'b0;
key_left = 1'b1;
key_right = 1'b1;
# 201
rst_n = 1'b1;
# 200;
press_left;
press_left;
press_left;
press_left;
press_left;
press_left;
press_left;
press_left;
press_left;
press_right;
press_right;
press_right;
press_right;
press_right;
press_right;
$stop;
end
task press_left;
begin
@ (posedge clk);
# 2;
key_left = 1'b0;
# 500
@ (posedge clk);
# 2;
key_left = 1'b1;
# 5000;
end
endtask
task press_right;
begin
@ (posedge clk);
# 2;
key_right = 1'b0;
# 500
@ (posedge clk);
# 2;
key_right = 1'b1;
# 5000;
end
endtask
endmodule
5.2仿真波形
在仿真中,模拟击打左球拍和击打有球拍的情况,从仿真波形中可以看出,当模拟击打球拍时,LED显示出乒乓球运动轨迹,再次击打球拍后,重新发球,数码管计分器数字变化。
六、下板实验
6.1引脚绑定
6.2下板实验
上一篇: 开荒_TextbookOrderingSystem
下一篇: mysql加锁读