二、按键消抖
因为是基于小梅哥开发板ACX720进行的开发设计,且后续有用到按键控制的功能,故本章进行按键消抖的程序设计以及功能验证,因为功能较为简单,modelsim仿真代码将不进行专门讲述。
在小梅哥教材中右讲解按键消抖的基本原理,这里不进行专门讲述,详情请参考小梅哥的视频教程,按键控制机制如下图:
如图所示,理论与实际图存在着抖动误差,但是一般的按键抖动误差为20ms左右,那在设计中,我将20ms设置为极限的抖动时间,那么通过延时等待这段时间再去进一步检测按键信号也是可行的,但是这就会与教材有所不同,及没有教材的反馈机制,但是一般使用过程中也不会有很高概率的“失效”现象。
如上图所示,按键按下 --> 等待延时 -->状态确认 --> 按键恢复 --> 结束,此流程非常适合采用状态机进行设计,状态机流程使用如上,按键按下消抖流程就可以实现了,代码如下,下述edge_check为简单的检沿动作,我将其例化成模块以进行调用,这里不再进行讲述:
module key_filter #
(
parameter DELY = 20
)
(
input clk_sys ,
input rst_sys ,
input timer_1ms ,
input timer_1s ,
//
input key_in ,
output key_out
);
// ********************************************************
// localparam
// ********************************************************
localparam IDLE = 3'd0 ;
localparam NAIT = 3'd1 ;
localparam KENA = 3'd2 ;
localparam PAIT = 3'd3 ;
localparam OVER = 3'd4 ;
// ********************************************************
// signal
// ********************************************************
wire pedge ;
wire nedge ;
reg [2:0] cstate = IDLE ;
reg [2:0] nstate = IDLE ;
reg [7:0] cnt_delay = 0 ;
reg delay_done = 0 ;
reg key_reg = 0 ;
// ********************************************************
// peocess
// ********************************************************
always @ ( posedge clk_sys )
begin
if( rst_sys )
cstate <= IDLE ;
else
cstate <= nstate ;
end
always @ ( * )
begin
case ( cstate )
IDLE : begin
if( nedge )
nstate = NAIT ;
else
nstate = IDLE ;
end
NAIT : begin
if( delay_done )
nstate = KENA ;
else
nstate = NAIT ;
end
KENA : begin
if( pedge )
nstate = PAIT ;
else
nstate = KENA ;
end
PAIT : begin
if( delay_done )
nstate = OVER ;
else
nstate = PAIT ;
end
OVER : nstate = IDLE ;
default: nstate = IDLE ;
endcase
end
always @ ( posedge clk_sys )
begin
if( rst_sys || pedge || nedge )
cnt_delay <= 0 ;
else if( timer_1ms )
cnt_delay <= cnt_delay + ~&cnt_delay ;
end
always @ ( posedge clk_sys )
begin
if( rst_sys )
delay_done <= 0 ;
else if(( cstate == NAIT || cstate == PAIT ) && cnt_delay == DELY )
delay_done <= 1 ;
else
delay_done <= 0 ;
end
always @ ( posedge clk_sys )
begin
if( cstate == KENA )
key_reg <= 1 ;
else if( cstate == OVER )
key_reg <= 0 ;
else ;
end
// ========================================================
//
// ========================================================
edge_detect u0_edge_detect
(
//input
.clk ( clk_sys ),
.sig_in ( key_in ),
//output
.p_edge ( pedge ),
.n_edge ( nedge )
);
edge_detect u1_edge_detect
(
//input
.clk ( clk_sys ),
.sig_in ( key_reg ),
//output
.p_edge ( key_out ),
.n_edge ( )
);
endmodule
进行完设计后,将丢按键消抖代码进行验证,可以进行modelsim仿真,也可进行上板验证,这里通过上板验证控制LED显示,显示代码如下:
module key_led #
(
parameter KNUM = 5
)
(
input clk_sys ,
input rst_sys ,
input timer_1ms ,
input timer_1s ,
//
input [KNUM-1:0] key_in ,
output reg [7:0] led_out
);
// ********************************************************
// signal
// ********************************************************
wire [KNUM-1:0] key_flag ;
wire key_rst ;
wire key_add ;
wire key_sub ;
wire key_lef ;
wire key_rih ;
// ********************************************************
// process
// ********************************************************
assign key_rst = key_flag[0] ; // 复位
assign key_add = key_flag[1] ; // 按键+
assign key_sub = key_flag[2] ; // 按键-
assign key_lef = key_flag[3] ; // 按键左移
assign key_rih = key_flag[4] ; // 按键右移
always @ ( posedge clk_sys )
begin
if( rst_sys || key_rst)
led_out <= 0 ;
else if( key_add )
led_out <= led_out + 1 ;
else if( key_sub )
led_out <= led_out - 1 ;
else if( key_lef )
led_out <= led_out << 1 ;
else if( key_rih )
led_out <= led_out >> 1 ;
else ;
end
// ========================================================
//
// ========================================================
key_filter u_key_filter[KNUM-1:0]
(
.clk_sys ( clk_sys ),
.rst_sys ( rst_sys ),
.timer_1ms ( timer_1ms ),
.timer_1s ( timer_1s ),
//
.key_in ( key_in ),
.key_out ( key_flag )
);
endmodule
如此本章内容实现就讲完了,最终的modelsim仿真以及上班实现就不再此进行公布。