提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
详细记录按键消抖的学习记录,以后如果有用到的地方可以及时回来回顾;对一些代码作出详细的注释,方便以后自己理解。
按键消抖其实和容易理解,按下去,弹上来,这是大多数按键的操作,机械式的操作就会带来我们不需要的变量,比如在刚刚按下去的时候,接触点断断续续,这个过程大约持续5ms-10ms,弹起来同理,这就是所谓的抖动。为了确保按键的精确性,所以要做消抖处理。
提示:以下是本篇文章正文内容,下面案例可供参考
一、如何消抖
既然知道了为什么抖动,那么就在按键抖动的时候不采样嘛,当按键在某个状态持续够某个时间时,再认为他被按下啦,这不就行了。
我们通常把这个时间设定为20ms(这不是绝对的,你可以长一点,或者短一点,不要太短,因为可能还是抖动),当该按键的状态发生变化时,变化后的状态是否持续20ms,如果有,则判定该按键有效,如果没有持续20ms,则判定为抖动。
二、模块划分
1.pll模块
这个简单,直接调用ip core就行,输入时钟50Mhz,输出时钟我设了两个50Mhz和100Mhz;下面是pll例化部分,我把pll的ip core 命名为u1_pll
pll u1_pll(
.clk_out1(clk_50M ), // output clk_50Mhz
.clk_out2(clk_100M ), // output clk_100Mhz
.reset (~rst_n ), // input reset
.locked ( ), // output locked
.clk_in1 (clk ) // input clk_50Mhz
);
2.key_debounce模块
第二个模块就是消抖模块,参考了黑金和正点原子,从TIME_VAL 递减,减完产生一个按键按下的信号或者是按键弹起的信号,是上升沿还是下降沿有key_value和key_flag共同juedin
//======================================================================
//Company :
//Filenam : .v
//Author :
//Created On : 2023-12-14 10:20
//Last Modified : 2023-12-14 18:10
//Description :
//
//
//======================================================================
module key_debounce(
input clk , //
input rst_n , //
input key , //
output reg key_value , //
output reg key_flag //
);
parameter FREQ = 50 ; // Mhz
parameter TIME_MAX = 20 ; // ms
localparam TIME_VAL = TIME_MAX * FREQ * 1000 ; //
reg [ 19:0 ] key_cnt ; //
reg key_r1 ; //
reg key_r2 ; //
/**************************************************************************
//
**************************************************************************/
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_r1 <= 1'b1;
key_r2 <= 1'b1;
end
else begin
key_r1 <= key;
key_r2 <= key_r1;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_cnt <= 20'd0;
end
else begin
if( key_r2 == !key_r1)begin
key_cnt <= TIME_VAL;
end
else begin
if( key_cnt > 20'd0)
key_cnt <= key_cnt - 1'b1;
else
key_cnt <= 20'd0;
end
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_value <= 1'b1;
key_flag <= 1'b0;
end
else if (key_cnt == 20'd1)begin
key_value <= key;
key_flag <= 1'b1;
end
else begin
key_value <= key_value;
key_flag <= 1'b0;
end
end
endmodule
3.key_count模块
实现的功能是,按键按下,四个led变化,刚开始led=4'b1111,全灭,按下一次,变为led=4'b1110;再按一次变为led=4'b1100;以此类推;
//======================================================================
//Company :
//Filenam : .v
//Author :
//Created On : 2023-12-14 18:22
//Last Modified :
//Description :
//
//
//======================================================================
`timescale 1ns / 1ps
module key_count(
input clk , //
input rst_n , //
input key_flag , //
input key_value , //
output reg [ 3:0 ] led //
);
reg [ 3:0 ] led_cnt ; //
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
led_cnt <= 4'b1111;
end
else if(key_flag&&!key_value)begin
led_cnt <= led_cnt + 1'b1;
end
else begin
led_cnt <= led_cnt ;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
led <= 4'b1111;
end
else begin
led <= led_cnt ;
end
end
endmodule
4.顶层模块key_ctrl
//======================================================================
//Company :
//Filenam : .v
//Author :
//Created On : 2023-12-14 18:33
//Last Modified :
//Description :
//
//
//======================================================================
`timescale 1ns / 1ps
module key_ctrl(
input clk , //
input rst_n , //
input key , //
output wire [ 3:0 ] led //
);
wire key_value ; //
wire key_flag ; //
wire clk_50M ; //
wire clk_100M ; //
pll u1_pll(
.clk_out1(clk_50M ), // output clk_50Mhz
.clk_out2(clk_100M ), // output clk_100Mhz
.reset (~rst_n ), // input reset
.locked ( ), // output locked
.clk_in1 (clk ) // input clk_50Mhz
);
key_debounce u2_debounce(
.clk ( clk ),
.rst_n ( rst_n ),
.key ( key ),
.key_value( key_value ), //
.key_flag ( key_flag ) //
);
key_count u3_count(
.clk ( clk ), //
.rst_n ( rst_n ), //
.key_flag ( key_flag ), //
.key_value( key_value ), //
.led ( led ) //
);
endmodule
三、总结
怎么说呐!也是在学习吧,做什么都慢慢积累吧,走的很慢,但在向前;
征途漫漫,奋勇向前!!!共勉