欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

程序员文章站 2022-07-02 16:14:47
...

设计目的
使用FPGA实验班设计一个数字逻辑系统,巩固数字逻辑电路的相关知识,锻炼熟练使用FPGA设计软件和硬件和独立完成项目设计的能力。

二、设计内容
2.1摘要
设计一个乒乓球游戏,实现游戏功能和计分功能。
通过开发板的按键实现左右球拍的击拍和游戏的复位;通过数码管显示游戏的比分;通过led显示乒乓球的运动轨迹。
2.2游戏规则
第一步:按下复位,led不亮,数码管显示比分00–00。
第二步:按下左球拍或者右球拍,发球,游戏开始,发球方向随机。
第三步:乒乓球在左半场/右半场并且靠近左侧/右侧的时候,左球拍/右球拍可以击球。如果在错误的时机击球或未成功接球,判负,对方加一分。
第四步:当有一方积得11分,游戏结束。再次开始游戏需要进行复位。

三、设计思路
3.2流程图
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

3.2顶层框图
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

3.3接口说明
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

名称 类型 封装管脚 说明
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分模块框图
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

四、代码实现
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仿真波形
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

在仿真中,模拟击打左球拍和击打有球拍的情况,从仿真波形中可以看出,当模拟击打球拍时,LED显示出乒乓球运动轨迹,再次击打球拍后,重新发球,数码管计分器数字变化。

六、下板实验
6.1引脚绑定
数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

6.2下板实验

数字逻辑电路与系统 课程设计:基于FPGA的乒乓球游戏

相关标签: fpga