有限状态机实现的软件消抖电路

Debouncing circuit(消抖电路)
Figure 5.8 Original and debounced waveforms.

debouncing scheme 2

// Debouncing circuit
module debouncing
(
    input wire clk,
    input wire reset,
    input wire sw, // 抖动的按钮或拨码开关输入信号
    output reg db_level, // 去抖动后的开关信号输出
    output reg db_tick // 每次输出宽度等于一个clk周期的脉冲信号
);

// 状态寄存器相关常量和变量定义
localparam [1:0]
    zero = 2'b00,
    wait0 = 2'b01,
    one = 2'b10,
    wait1 = 2'b11;
reg [1:0] state_reg;
reg [1:0] state_next;

// 状态寄存器时序逻辑
always @(posedge clk, posedge reset)
begin
    if (reset)
        state_reg <= zero;
    else
        state_reg <= state_next;
end


// 计数器相关常量和变量定义
localparam N=21; // 2^N * 20ns 约等于 40ms, 此处假定clk时钟频率=50MHz, 即周期=20ns
localparam COUNTER_MAX={N{1'b1}};
localparam COUNTER_ZERO={N{1'b0}};
reg [N-1:0] cnt_reg;
wire [N-1:0] cnt_next;
reg cnt_load;
reg cnt_is_decreasing;
wire cnt_is_finished;

// 计数器时序逻辑
always @(posedge clk, posedge reset)
begin
    if (reset)
        cnt_reg <= COUNTER_ZERO;
    else
        cnt_reg <= cnt_next;
end

// 计数器的 next-state 组合逻辑
assign cnt_next =
    (cnt_load)? (COUNTER_MAX) :  // load cnt_next=COUNTER_MAX
    (cnt_is_decreasing)? (cnt_reg - 1) :  // cnt_next=(cnt_reg - 1)
    cnt_reg;  // cnt_next=cnt_reg

// 计数器是否到达计数终点
assign cnt_is_finished = (COUNTER_ZERO == cnt_next);

// 有限状态机控制通道的 next-state 组合逻辑
always @*
begin
    state_next = state_reg;  // default state: the same
    cnt_load = 1'b0;  // default
    cnt_is_decreasing = 1'b0;  // default
    db_tick = 1'b0;  // default
    case (state_reg)
        zero:
            begin
                db_level = 1'b0;
                if (sw)
                    begin
                        state_next = wait1;
                        cnt_load = 1'b1;
                    end
            end
        wait1:
            begin
                db_level = 1'b0;
                if (sw)
                    begin
                        cnt_is_decreasing = 1'b1;
                        if (cnt_is_finished)
                            begin
                                state_next = one;
                                db_tick = 1'b1;
                            end
                    end
                else
                    state_next = zero;
            end
        one:
            begin
                db_level = 1'b1;
                if (~sw)
                    begin
                        state_next = wait0;
                        cnt_load = 1'b1;
                    end
            end
        wait0:
            begin
                db_level = 1'b1;
                if (~sw)
                    begin
                        cnt_is_decreasing = 1'b1;
                        if (cnt_is_finished)
                            begin
                                state_next = zero;
                            end
                    end
                else
                    state_next = one;
            end
        default:
            begin
            end
    endcase
end

endmodule

相关文章: