详解MCU独立按键消抖原因方法统统都有.docx
《详解MCU独立按键消抖原因方法统统都有.docx》由会员分享,可在线阅读,更多相关《详解MCU独立按键消抖原因方法统统都有.docx(9页珍藏版)》请在冰豆网上搜索。
详解MCU独立按键消抖原因方法统统都有
详解MCU独立按键消抖:
原因、方法统统都有
简单的说,进入了电子,不管是学纯模拟,还是学单片机,像DSP、ARM等处理器,或者是我们的FPGA,一般没有不用到按键的地方(按键:
人机交互控制,主要用于对系统的控制,信号的释放等)。
因此在这里,FPGA上应用的按键消抖动,也不得不讲!
一、为什么要消抖动
在按键被按下的短暂一瞬间,由于硬件上的抖动,往往会产生几毫秒的抖动,在这时候若采集信号,势必导致误操作,甚至系统崩溃;同样,在释放按键的那一刻,硬件上会相应的产生抖动,会产生同样的后果。
因此,在模拟或者数字电路中,我们要避免在最不稳定的时候采集信号进行操作。
对此,一般产用消抖动的原理,其可分为以下三种:
(1)延时
(2)N次低电平计数
(3)低通滤波
在数字电路中,一般采用第1、2种方法(后文中将详细介绍)。
二、各种消抖动
1、模拟电路按键消抖动
对于模拟电路中,一般消抖动用的是电容消抖动或者施密特触发等电路,再次不做具体介绍。
图片
2、单片机中按键消抖动
对于单片机中的按键消抖动,本节Bingo根据自己当年写过的单片机其中的一个代码来讲解,代码如下所示:
unsignedcharkey_sCAN(void)
{
if(key==0)//检测到被按下
{
delay(5);//延时5ms,消抖
if(key!
=0)
retrurn0;//是抖动,返回退出
while(!
key1);//确认被按下,等下释放
delay(5);//延时5ms,消抖
while(!
key1);//确认被释放
return1;//返回按下信号
}
return0;//没信号
}
针对以上代码,消抖动的顺序如下所示:
(1)检测到信号
(2)延时5ms,消抖动
(3)继续检测信号,确认是否被按下
a.是,则开始等待释放
b.否,则返回0,退出
(4)延时5ms,消抖动
(5)确认,返回按下信号,退出
当然,在单片机中也可以循环计数来确认是否被按下。
Bingo认为如此,太耗MCU资源,因此再次不做讲述。
3、FPGA中的按键消抖动
对于FPGA中的消抖动,很多教科书上都没有讲述。
但Bingo觉得这个很有必要。
对于信号稳定性以及准确性分析,按键信号必须有一个稳定的脉冲,不然对系统稳定性有很大的干扰。
此处Bingo用两种方法对FPGA中按键消抖动分析。
其中,第一种是通过状态机的使用直接移植以上MCU的代码,这个思想在FPGA状态机中很重要。
第二种,通过循环n次计数的方法来确认是否真的被按下,这种方法很适用于FPGA这种高速并行器件中。
一是,利用状态机移植MCU按键消抖动。
此模块由Bingo无数次修改测试最后成型的代码,在功能上可适配n个按键,在思想上利用单片机采用了单片机消抖动的思想。
具体代码实现过程请有需要的自行分析,本模块移植方便,Verilog代码如下所示:
/*************************************************
*ModuleName:
key_scan_jitter.v
*Engineer:
CrazyBingo
*TargetDevice:
EP2C8Q208C8
*Toolversions:
QuartusII11.0
*CreateDate:
2011-6-26
*Revision:
v1.0
*Description:
**************************************************/
modulekey_scan_jitter
#(
parameterKEY_WIDTH=2
)
(
inputclk,
inputrst_n,
input[KEY_WIDTH-1:
0]key_data,
outputkey_flag,
outputreg[KEY_WIDTH-1:
0]key_value
);
reg[19:
0]cnt;//delay_5ms(249999)
reg[2:
0]state;
//-----------------------------------
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
cnt<=20'd0;
else
begin
cnt<=cnt+1'b1;
if(cnt==20'd249999)
cnt<=20'd0;
end
end
//-----------------------------------
regkey_flag_r;
reg[KEY_WIDTH-1:
0]key_data_r;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
key_flag_r<=1'b0;
key_value<={KEY_WIDTH{1'b0}};
end
elseif(cnt==20'd249999)//Delay_5ms
begin
case(state)
0:
begin
if(key_data!
={KEY_WIDTH{1'b1}})
state<=1;
else
state<=0;
end
1:
begin
if(key_data!
={KEY_WIDTH{1'b1}})
state<=2;
else
state<=0;
end
2:
begin
key_flag_r<=1'b1;
key_value<=key_data;//lockthekey_value
state<=3;
end
3:
begin
key_flag_r<=1'b0;//readthekey_value
if(key_data=={KEY_WIDTH{1'b1}})
state<=4;
else
state<=3;
end
4:
begin
if(key_data=={KEY_WIDTH{1'b1}})
state<=0;
else
state<=4;
end
endcase
end
end
//---------------------------------------
//Capturethefallingendgeofthekey_flag
regkey_flag_r0,key_flag_r1;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
key_flag_r0<=0;
key_flag_r1<=0;
end
else
begin
key_flag_r0<=key_flag_r;
key_flag_r1<=key_flag_r0;
end
end
assignkey_flag=key_flag_r1&~key_flag_r0;
endmodule
信号线说明如下:
clk
系统最高时钟
rst_n
系统复位信号
Key_data
按键信号(可根据需要配置为n位)
Key_flag
按键确认信号
Key_vaule
按键返回值
雷同上述MCU按键消抖动的状态,此模块可以模拟成一下5个状态,见statemachine:
图片
二是,循环n次计数消抖动。
同样,此模块也是Bingo无数次修改测试最后成型的代码,利用了更少的资源,更适用于并行高速FPGA的性能要求。
具体代码实现过程请有需要的自行分析,本模块通过相关时钟的适配,n次计数来确认按键信号,Verilog代码如下所示:
/*************************************************
*ModuleName:
key_scan.v
*Engineer:
CrazyBingo
*TargetDevice:
EP2C8Q208C8
*Toolversions:
QuartusII11.0
*CreateDate:
2011-6-25
*Revision:
v1.0
*Description:
**************************************************/
modulekey_scan
#(
parameterKEY_WIDTH=2
)
(
inputclk,//50MHz
inputrst_n,
input[KEY_WIDTH-1:
0]key_data,
outputkey_flag,
outputreg[KEY_WIDTH-1:
0]key_value
);
//---------------------------------
//escapethejitters
reg[19:
0]key_cnt;//scancounter
reg[KEY_WIDTH-1:
0]key_data_r;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
key_data_r<={KEY_WIDTH{1'b1}};
key_cnt<=0;
end
else
begin
key_data_r<=key_data;//lockthekeyvalue
if((key_data==key_data_r)&&(key_data!
={KEY_WIDTH{1'b1}}))//20msescapejitter
begin
if(key_cnt<20'hfffff)
key_cnt<=key_cnt+1'b1;
end
elsekey_cnt<=0;
end
end
wirecnt_flag=(key_cnt==20'hffffe)?
1'b1:
1'b0;//!
!
//-----------------------------------
//surethekeyispressed
regkey_flag_r;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
key_flag_r<=0;
key_value<=0;
end
elseif(cnt_flag)
begin
key_flag_r<=1;
key_value<=key_data;//lockedthedata
end
else//letgoyourhand
key_flag_r<=0;//lockthekey_value
end
//---------------------------------------
//Capturetherisingendgeofthekey_flag
regkey_flag_r0,key_flag_r1;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
key_flag_r0<=0;
key_flag_r1<=0;
end
else
begin
key_flag_r0<=key_flag_r;
key_flag_r1<=key_flag_r0;
end
end
assignkey_flag=~key_flag_r1&key_flag_r0;
endmodule