|按键控制 LED 翻转

按键控制 LED 翻转

作者: 石志超更新于: 2026/2/27

含两拍同步 + 消抖 + 异步复位同步释放

module top (
    input        sys_clk,
    input        sys_rst_n,
    input        key_n,        // 按键(低有效)
    output [3:0] led
);

// ── 异步复位同步释放 ──
reg rst_r1, rst_r2;
always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin rst_r1 <= 0; rst_r2 <= 0; end
    else            begin rst_r1 <= 1; rst_r2 <= rst_r1; end
end
wire rst_n = rst_r2;

// ── 两拍同步 ──
reg key_r1, key_r2;
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin key_r1 <= 1; key_r2 <= 1; end
    else        begin key_r1 <= key_n; key_r2 <= key_r1; end
end

// ── 消抖(20ms @ 50MHz)──
parameter CNT_MAX = 1_000_000;
reg [19:0] db_cnt;
reg        key_db;
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin db_cnt <= 0; key_db <= 1; end
    else if (key_r2 != key_db) begin
        if (db_cnt >= CNT_MAX - 1) begin db_cnt <= 0; key_db <= key_r2; end
        else                        db_cnt <= db_cnt + 1;
    end else db_cnt <= 0;
end

// ── 下降沿检测 + 翻转 ──
reg key_prev;
reg [3:0] led_r;
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin key_prev <= 1; led_r <= 4'b0000; end
    else begin
        key_prev <= key_db;
        if (key_prev && !key_db) led_r <= ~led_r;
    end
end

assign led = ~led_r;
endmodule