历史上的今天
今天是:2025年03月11日(星期二)
2018年03月11日 | 非同于MCU的独立按键消抖动
2018-03-11 来源:eefocus
简单的说,进入了电子,不管是学纯模拟,还是学单片机,DSP、ARM等处理器,或者是我们的FPGA,一般没有不用到按键的地方。按键:人机交互控制,主要用于对系统的控制,信号的释放等。因此在这里,FPGA上应用的按键消抖动,也不得不讲!
一、为什么要消抖动

如上图所示,在按键被按下的短暂一瞬间,由于硬件上的抖动,往往会产生几毫秒的抖动,在这时候若采集信号,势必导致误操作,甚至系统崩溃;同样,在释放按键的那一刻,硬件上会相应的产生抖动,会产生同样的后果。因此,在模拟或者数字电路中,我们要避免在最不稳定的时候采集信号,进行操作。
对此一般产用消抖动的原理。一般可分为以下几种:
(1)延时
(2)N次低电平计数
(3)低通滤波
在数字电路中,一般产用(1)(2)种方法。后文中将详细介绍。
二、各种消抖动
1. 模拟电路按键消抖动
对于模拟电路中,一般消抖动用的是电容消抖动或者施密特触发等电路,再次不做具体介绍。
2. 单片机中按键消抖动
对于单片机中的按键消抖动,本节Bingo根据自己当年写过的单片机其中的一个代码来讲解,代码如下所示:
unsigned char key_sCAN(void)
{
if(key == 0) //检测到被按下
{
delay(5); //延时5ms,消抖
if(key != 0)
retrurn 0; //是抖动,返回退出
while(!key1); // 确认被按下,等下释放
delay(5); //延时5ms,消抖
while(!key1); //确认被释放
return 1; //返回按下信号
}
return 0; //没信号
}
针对以上代码,消抖动的顺序如下所示:
(1)检测到信号
(2)延时5ms,消抖动
(3)继续检测信号,确认是否被按下
a) 是,则开始等待释放
b) 否,则返回0,退出
(4)延时5ms,消抖动
(5)确认,返回按下信号,退出
当然在单片机中也可以循环计数来确认是否被按下。Bingo认为如此,太耗MCU资源,因此再次不做讲述。
3. FPGA中的按键消抖动
对于FPGA中的消抖动,很多教科书上都没有讲述。但Bingo觉得这个很有必要。对于信号稳定性以及准确性分析,按键信号必须有一个稳定的脉冲,不然对系统稳定性有很大的干扰。
此处Bingo用两种方法对FPGA中按键消抖动分析。其中第一种是通过状态机的使用直接移植以上MCU的代码,这个思想在FPGA状态机中很重要。第二种,通过循环n次计数的方法来确认是否真的被按下,这种方法很实用在FPGA这种高速并行器件中。
(1)利用状态机移植MCU按键消抖动
此模块由Bingo无数次修改测试最后成型的代码,在功能上可适配n个按键,在思想上利用单片机采用了单片机消抖动的思想。具体代码实现过程请有需要的自行分析,本模块移植方便,Verilog代码如下所示:
/*************************************************
* Module Name : key_scan_jitter.v
* Engineer : Crazy Bingo
* Target DevICe : EP2C8Q208C8
* Tool versions : QUARTus II 11.0
* Create Date : 2011-6-26
* Revision : v1.0
* Description :
**************************************************/
module key_scan_jitter
#(
parameter KEY_WIDTH = 2
)
(
input clk,
input rst_n,
input [KEY_WIDTH-1:0] key_data,
output key_flag,
output reg [KEY_WIDTH-1:0] key_value
);
reg [19:0] cnt; //delay_5ms(249999)
reg [2:0] state;
//-----------------------------------
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 20'd0;
else
begin
cnt <= cnt + 1'b1;
if(cnt == 20'd249999)
cnt <= 20'd0;
end
end
//-----------------------------------
reg key_flag_r;
reg [KEY_WIDTH-1:0] key_data_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_flag_r <= 1'b0;
key_value <= {KEY_WIDTH{1'b0}};
end
else if(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; //LOCk the key_value
state <= 3;
end
3:
begin
key_flag_r <= 1'b0; //read the key_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
//---------------------------------------
//Capture the falling endge of the key_flag
reg key_flag_r0,key_flag_r1;
always@(posedge clk or negedge rst_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
assign key_flag = key_flag_r1 & ~key_flag_r0;
endmodule
信号线说明如下:
clk
系统最高时钟
rst_n
系统复位信号
Key_data
按键信号(可根据需要配置为n位)
Key_flag
按键确认信号
Key_vaule
按键返回值
雷同上述MCU按键消抖动的状态,此模块可以模拟成一下5个状态,见state machine:
(2)循环n次计数消抖动
同样,此模块也是Bingo无数次修改测试最后成型的代码,利用了更少的资源,更适用于并行高速FPGA的性能要求。具体代码实现过程请有需要的自行分析,本模块通过相关时钟的适配,n次计数来确认按键信号,Verilog代码如下所示:
/*************************************************
* Module Name : key_sCAN.v
* Engineer : Crazy Bingo
* Target DevICe : EP2C8Q208C8
* Tool versions : QUARTus II 11.0
* Create Date : 2011-6-25
* Revision : v1.0
* Description :
**************************************************/
module key_sCAN
#(
parameter KEY_WIDTH = 2
)
(
input clk, //50MHz
input rst_n,
input [KEY_WIDTH-1:0] key_data,
output key_flag,
output reg [KEY_WIDTH-1:0] key_value
);
//---------------------------------
//escape the jitters
reg [19:0] key_cnt; //scan counter
reg [KEY_WIDTH-1:0] key_data_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_data_r <= {KEY_WIDTH{1'b1}};
key_cnt <= 0;
end
else
begin
key_data_r <= key_data; //LOCk the key value
if((key_data == key_data_r) && (key_data != {KEY_WIDTH{1'b1}})) //20ms escape jitter
begin
if(key_cnt < 20'hfffff)
key_cnt <= key_cnt + 1'b1;
end
else key_cnt <= 0;
end
end
wire cnt_flag = (key_cnt == 20'hffffe) ? 1'b1 : 1'b0;//!!
//-----------------------------------
//sure the key is pressed
reg key_flag_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_flag_r <= 0;
key_value <= 0;
end
else if(cnt_flag)
begin
key_flag_r <= 1;
key_value <= key_data; //locked the data
end
else //let go your hand
key_flag_r <= 0; //lock the key_value
end
//---------------------------------------
//Capture the rising endge of the key_flag
reg key_flag_r0,key_flag_r1;
always@(posedge clk or negedge rst_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
assign key_flag = ~key_flag_r1 & key_flag_r0;
endmodule
上一篇:单片机应用编程知识介绍
史海拾趣
|
内置与外置天线及内置天线技术要求 天线分为内置与外置,外置主要使用螺旋或者PCB,螺旋天线一般带宽比较好也比较常用,PCB 天线比较容易调频率易于设计,但爱立信有两项重要专利,所以在欧美市场上很少其他厂商使用。还有一种假内置天线,其实 ...… 查看全部问答> |
|
norflash支持片上运行,nandflash不支持。那通常所说的在norflash上运行的程序是不是可以不需要ram? 如果我想做一个最小的ARM系统,一个2440芯片+一片norflash可行吗?不用操作系统,只运行一些百K左右大的.bin文件,也不用考虑程序的运行速度。 ...… 查看全部问答> |
|
小弟使用的是C8051F020芯片 以太网接口芯片是CP2201 由于开发使用芯片自带的库文件 函数和socket有些类似 程序基本实现将从PC收到的数据再次传回去 发送发送一段时间后(10ms或100ms) 单片机将不收数据了 不知道是什么原因?… 查看全部问答> |
|
STM32可以编译包括运行,但是收不到数据。很郁闷。 公司台式电脑没串口,用的是USB转串口,相当于虚拟串口,串口调试助手,是用COM3口。下述程序可以运行,LED也会闪,但是串口调试助手上就是收不到数据。 请帮忙看看,十分感谢! 附近 ...… 查看全部问答> |
|
大家好,我按着TI的资料做了一块2401的板子,做出来后不要说用来做调试了,就是连都不能连上.接下来的工作根本无法进行.后来找JTAG的资料来研究,发现EUM0和EUM1是用来作为接收来自仿真器的中断 ...… 查看全部问答> |
|
最近在移植UCOS到MCF52259中,我是新手啊,遇到个问题(如标题),我有几个疑问啊:1.书上说,在正确设置了软中断向量或TRAP向量,使之指向OSCtxSw()函数的前提下,CPU将会执行OSCtxSw函数 我想问这个正确设置的问题:我这里是这样的:#d ...… 查看全部问答> |
|
我用这个28035运行其他的程序能够运行,应该说明系统时钟应该能够支持系统的运行。 但是我现在在做一个28035+TOPWAY 的液晶屏的显示就是显示不出来。 以前我在MSP430F149上已经实现了。这次只是换到DSP28035上就 ...… 查看全部问答> |




