我们写按键消抖Verilog代码一般是用一个计数器来获得20ms的时间区间,最后获得一个稳定的按键状态输出。要么是按键按下事件,要么是按键释放事件。我们再学习状态机的时候,可以考虑用状态机的方式来写按键消抖代码。
以下代码是学员再练习状态机书写的过程中写的基于状态机的按键消抖代码,可以作为学习研究之用。
//使用状态机实现按键消抖
//学员-陈科霖
module debounce_fsm
(
input clk,
input rst_n,
input key,
output reg key_flag,//按键事件 (按下or释放)
output reg key_value
);
parameter IDLE = 2'd1;
parameter s1 = 2'd2;
parameter s2 = 2'd3;//消抖后状态
parameter SUM = 100;
reg [1:0] current_state;
reg [1:0] nex_state;
reg key_event;
reg [25:0] counter;
reg key_reg;
//三段式状态机 第一段
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
current_state <= IDLE;
else
current_state <= nex_state;
end
//第二段(控制状态迁移)
always @(*)begin
case(current_state)
IDLE :
if(key_reg != key)
nex_state = s1;
else
nex_state = IDLE;
s1 :
if(counter == SUM)
nex_state = s2;
else
nex_state = s1;
s2 :
nex_state = IDLE;
endcase
end
//第三段(产生key_flag和key_value)
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
key_flag <= 1'b0;
key_value <= 1'b1;
end
else if(current_state == s2)begin
key_flag <= 1'b1;
key_value <= key_reg;
end
else begin
key_flag <= 1'b0;
key_value <= 1'b0;
end
end
//消抖延时计数器 20ms
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
counter <= 1'b0;
else if(key_reg != key && current_state == IDLE)begin
counter <= 1'b0;
end
else
if(counter < SUM && current_state == s1 && key_event)
counter <= counter + 1'b1;
else begin
counter <= counter;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
key_reg <= 1'b1;
else
key_reg <= key;
end
endmodule
发表回复