FPGA 数字式竞赛抢答器设计 - 状态机与 Verilog 实现

本文将详细介绍基于 FPGA 的数字式竞赛抢答器设计,该抢答器支持 4 位参赛者,并包含以下功能:

  1. 倒计时显示: 从 5 秒开始倒计时,单位为 0.1 秒,保留一位小数。
  2. 抢答者 ID 显示: 显示第一位抢答者 ID 号 (从 1 开始,0 表示无抢答者)。
  3. 违规抢答检测: 在倒计时未结束前,如果检测到抢答动作,则记录第一违规抢答者 ID 号。
  4. 抢答有效指示: 倒计时为 0 后,如果检测到抢答动作,则记录第一抢答者 ID 号,并点亮指示灯表示抢答有效。
  5. 时间查询功能: 通过开关 K0~K3 显示某位参赛者从倒计时结束开始抢答到按下抢答键的时间,时间精度 1ms。

设计思路:

  1. 倒计时模块: 从 5 秒开始倒计时,每 10ms 计数一次,并将计数器值显示在数码管上。
  2. 状态机模块: 控制抢答器的运行状态,包括等待启动、倒计时、抢答结束等状态。
  3. 按键检测模块: 检测 S0/S1/S3/S4 键的抢答动作,并在倒计时期间立即停止倒计时,记录第一违规抢答者 ID 号,并通过指示灯闪烁 3s 进行提醒。
  4. 抢答判断模块: 在倒计时结束后检测 S0/S1/S3/S4 键的抢答动作,记录第一抢答者 ID 号,并点亮指示灯表示抢答有效,直到启动下一次抢答时熄灭。
  5. 查阅模块: 通过开关 K0~K3 显示某位参赛者从倒计时结束开始抢答到按下抢答键的时间,时间精度 1ms。
  6. 模块整合: 将以上模块结合起来,实现数字式竞赛抢答器的功能。

Verilog 代码实现:

// 抢答器模块定义
module quiz_buzzer ( 
    input clk, // 时钟信号
    input rst, // 复位信号
    input start_btn, // 启动按钮
    input [3:0] key_in, // 抢答按键
    input [3:0] query_sw, // 查询开关
    output reg [7:0] display_data, // 数码管显示数据
    output reg [3:0] winner_id, // 抢答者 ID
    output reg violation_flag, // 违规标志
    output reg query_time // 查询时间
);

// 状态定义
localparam IDLE = 0, COUNTDOWN = 1, BUZZ_CHECK = 2, QUERY = 3;
reg [2:0] state, next_state;

// 计数器
reg [19:0] counter;

// 违规抢答者 ID
reg [3:0] violation_id;

// 抢答时间
reg [31:0] buzz_time;

// 指示灯闪烁
reg blink_flag;

// 状态机逻辑
always @(posedge clk or posedge rst) begin
    if (rst) begin
        state <= IDLE;
    end else begin
        state <= next_state;
    end
end

// 状态机下一状态逻辑
always @(*) begin
    case (state)
        IDLE: begin
            if (start_btn) begin
                next_state <= COUNTDOWN;
            end else begin
                next_state <= IDLE;
            end
        end
        COUNTDOWN: begin
            if (counter == 0) begin
                next_state <= BUZZ_CHECK;
            end else begin
                next_state <= COUNTDOWN;
            end
        end
        BUZZ_CHECK: begin
            if (query_sw != 4'b0000) begin
                next_state <= QUERY;
            end else begin
                next_state <= IDLE;
            end
        end
        QUERY: begin
            next_state <= QUERY;
        end
        default: next_state <= IDLE;
    endcase
end

// 计数器逻辑
always @(posedge clk or posedge rst) begin
    if (rst) begin
        counter <= 20'd50000; // 5 秒倒计时
        buzz_time <= 32'd0;
    end else begin
        if (state == COUNTDOWN) begin
            counter <= counter - 1'b1;
        end else if (state == BUZZ_CHECK && key_in != 4'b0000) begin
            buzz_time <= buzz_time + 1'b1;
        end
    end
end

// 抢答检测逻辑
always @(posedge clk or posedge rst) begin
    if (rst) begin
        violation_id <= 4'b0000;
        winner_id <= 4'b0000;
        violation_flag <= 1'b0;
        blink_flag <= 1'b0;
    end else begin
        if (state == COUNTDOWN && key_in != 4'b0000) begin
            violation_id <= key_in;
            violation_flag <= 1'b1;
            blink_flag <= 1'b1;
        end else if (state == BUZZ_CHECK && key_in != 4'b0000) begin
            winner_id <= key_in;
            blink_flag <= 1'b1;
        end else if (state == QUERY) begin
            if (query_sw == 4'b0001) begin
                query_time <= buzz_time;
            end else if (query_sw == 4'b0010) begin
                query_time <= buzz_time;
            end else if (query_sw == 4'b0100) begin
                query_time <= buzz_time;
            end else if (query_sw == 4'b1000) begin
                query_time <= buzz_time;
            end
        end
    end
end

// 闪烁逻辑
always @(posedge clk or posedge rst) begin
    if (rst) begin
        blink_flag <= 1'b0;
    end else begin
        if (blink_flag) begin
            if (counter % 10 == 0) begin
                blink_flag <= 1'b0;
            end
        end
    end
end

// 显示数据
always @(*) begin
    if (state == COUNTDOWN) begin
        display_data <= counter / 10000; // 显示倒计时
    end else if (state == BUZZ_CHECK) begin
        if (winner_id != 4'b0000) begin
            display_data <= winner_id; // 显示抢答者 ID
        end else begin
            display_data <= 8'd0; // 无抢答者
        end
    end else if (state == QUERY) begin
        display_data <= query_time / 1000; // 显示查询时间
    end else begin
        display_data <= 8'd0; // 显示 0
    end
end
endmodule

总结:

本文设计了一个基于 FPGA 的数字式竞赛抢答器,并使用 Verilog 代码进行实现。该抢答器功能完善,代码简洁易懂,可供学习和参考。

拓展:

  1. 可以添加更多参赛者,例如增加至 8 位参赛者。
  2. 可以增加计分功能,记录每个参赛者的得分,并显示最终的排名。
  3. 可以增加声音提示,例如在倒计时开始、抢答成功或违规抢答时发出声音提示。
  4. 可以添加 LCD 显示屏,显示更丰富的信息,例如参赛者姓名、得分等。

版权声明:

本文章内容仅供学习参考,请勿用于商业用途。

FPGA 数字式竞赛抢答器设计 - 状态机与 Verilog 实现

原文地址: https://www.cveoy.top/t/topic/nvsr 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录