电子拔河游戏机设计(Verilog+QuartusII)
本文基于实际工程代码,完整解析一个电子拔河游戏机的FPGA实现方案,适合初学者和硬件开发爱好者参考。
项目简介
名称:电子拔河游戏机 / Verilog / QuartusII
软件:QuartusII
语言:Verilog
代码功能
电子拔河游戏机是一种能容纳甲乙双方参赛或甲乙双方加裁判的三人游戏电路。由一排LED发光二极管表示拔河的“电子绳”。由甲、乙二人通过按钮开关使发光的LED管向自己一方的终点移动,当亮点移到任何一方的终点时,则该方获胜,连续比赛多局以定胜负。
其任务和要求如下:
1)由裁判下达比赛开始命令后,甲乙双方才能输入信号,否则,由于电路具有自锁功能,使输入信号无效。
2)“电子绳”至少由多个LED管构成,裁判下达“比赛开始”命令后,位于“电子绳”中点的LED管发亮。甲、乙二人通过按钮开关使发光的LED管向自己一方的终点移动,并阻止其向对方延伸。当点亮的LED管到达某一方的终点时,该方获胜。此时通过自锁功能锁定电路,使输入不再有效,必须由裁判再次发出“比赛开始”命令时方能开始下一次比赛。
3)某方赢一次,由计分电路自动给该方加分一次,通过多次比赛以定胜负。
本代码已使用小脚丫开发板进行功能验证

代码实现思路
整体采用模块化设计,核心为有限状态机(FSM)驱动的LED灯带移位与分数统计。按键信号经消抖处理后触发状态转移,实现比赛逻辑。数码管显示模块将分数转换为段码输出,保证实时反馈。各模块职责分明,便于维护与扩展。
- 设计亮点:
-
用移位寄存器实现灯带动态效果 -
FSM管理比赛流程与计分 -
按键消抖提升可靠性 -
数码管实时显示分数
-
代码结构
bahe_game:顶层模块,连接时钟、复位、按键、LED与数码管,实例化各子模块。key_debounce:按键消抖,输出稳定的按键上升沿脉冲。bahe_ctrl:比赛控制,管理状态机、LED灯带移位与分数统计。display:数码管显示,将分数转换为段码输出。
部分代码展示
module?bahe_ctrl(
input clk_in,//标准时钟,12MHz
input reset_n,//复位信号,低有效?
input restart,//裁判控制重新开始
input player_1,//选手1
input player_2,//选手2
output?[7:0]?led,//8个led
output reg?[3:0]?score_1,//选手1分数
output reg?[3:0]?score_2//选手2分数
);
parameter s_idle=3'd0;
parameter s_start=3'd1;
parameter s_left_shift=3'd2;
parameter s_right_shift=3'd3;
parameter s_win_1=3'd4;
parameter s_win_2=3'd5;
reg?[2:0]?state=3'd0;
reg?[7:0]?game_led=8'b00011000;
assign led=~game_led;//低电平亮
always@(posedge clk_in)
if(!reset_n)
state<=s_idle;
else
case(state)
s_idle://复位状态
if(restart)
state<=s_start;
else
state<=s_idle;
s_start:
if(game_led==8'b11000000)
state<=s_win_1;//1号赢
elseif(game_led==8'b00000011)
state<=s_win_2;//2号赢
else
if(player_1)
state<=s_left_shift;//led左移
elseif(player_2)
state<=s_right_shift;//led右移
else
state<=s_start;
s_left_shift:
state<=s_start;//led左移
s_right_shift:
state<=s_start;//led右移
s_win_1:
if(score_1==4'd9)//先赢9局者获胜
? state<=s_win_1;//1号赢
else
if(restart)
state<=s_start;//重新开始
else
state<=s_win_1;//1号赢
s_win_2:
if(score_2==4'd9)//先赢9局者获胜
? state<=s_win_2;//2号赢
else
if(restart)
state<=s_start;//重新开始
else
state<=s_win_2;//2号赢
default:;
endcase
always@(posedge clk_in)
if(!reset_n)
game_led<=8'b00011000;//复位
else
if(restart)
game_led<=8'b00011000;//重新开始
else
if(state==s_left_shift)//led左移
game_led<=game_led<<1;//led左移
elseif(state==s_right_shift)//led右移
game_led<=game_led>>1;//led右移
else
;
//积分累计1
always@(posedge clk_in)
if(!reset_n)
score_1<=4'd0;
else
if(state==s_start?&&?game_led==8'b11000000)
score_1<=score_1+4'd1;
//积分累计2
always@(posedge clk_in)
if(!reset_n)
score_2<=4'd0;
else
if(state==s_start?&&?game_led==8'b00000011)
score_2<=score_2+4'd1;
endmodule
466