本帖最后由 jj1989 于 2013-12-15 18:56 编辑
按键消抖有多种方法,初学者一般采用延时来达到消抖的目的。一般的延时消抖分两种:一种是先判断有键按下,延时几十毫秒再判断有无键按下,有则执行按键对应的程序。另一种是在延时几十毫秒之后,判断有无键按下;若有键按下,不立即响应按键程序,而是进入一个循环,循环的条件是有键按下。这样当松开按键后,才跳出循环,执行按键程序。
上述两种按键消抖都存在一定的问题:前者实际上无法达到真正的消抖。后者在松开按键的时候才响应,如果一直按住键,程序就进入了死循环。
这里介绍一种比较可靠的按键消抖,利用中断消抖。这里使用Syss
tick
(系统滴答定时器)定时中断。 整个消抖的流程如下:
1. Sysstick每1ms中断一次,在中断程序中判断是否有键按下;
2.有键按下,计数变量kcount加1,否则kcount清零;
3.当kcount的值大于等于32,即按键按下32ms之后,表示有键按下,此时设置相应的按键标志;
4.按键处理程序根据标志来执行相应程序;
具体程序如下:
/*******************
*@brief This function handles SysTickHandler.
*@param None
*@retval : None
******************/
void SysTick_Handler(void) //这是系统自身的Sysstick中断函数,只需要在其中调用我们的按键扫描函数即可
{
Key_Scan(); //中断程序中调用按键扫描函数
}
/****************
* 函数名:Key_Scan
* 描述 :检测是否有按键按下
* 输入 :GPIOx:x 可以是 A,B,C,D或者 E
* GPIO_Pin:待读取的端口位
* 输出 :flag (flag=1,表示有按键按下,flag=0,表示无键按下)
*****************/
void Key_Scan(void)
{
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)== KEY_ON )
{
kcount++; //有键按下,计数kcount加1
if(kcount>=32) //1MS中断一次,kcount大于等于32,即按键已按下32ms
{
if(label==0) //判断有没有重按键,1为有,0为没有
{
flag=1; //设置按键标志
kcount=0;
label=1; //设置重按键标志
}
else
kcount=0;
}
else
flag=0;
}
else //无按键按下
{
kcount=0; //清零kcount
flag=0; //清除按键标志
label=0; //清除重按键标志
}
}
/***************************************
* 函数名:main
* 描述 :主函数
* 输入 :无
* 输出 :无
****************************************/
int main(void)
{
LED_GPIO_Config(); //初始化
Key_GPIO_Config();
LED2(0);
SysTick_Init(); //配置SysTick 为1ms中断一次
SysTick->CTRL|= SysTick_CTRL_ENABLE_Msk; // 使能滴答定时器
while(1)
{
if(flag )
{
flag=0;
/*LED1翻转*/
GPIO_WriteBit(GPIOC,GPIO_Pin_2, (BitAction)(1-(GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_2))));
}
}
}
程序分析:
当判断按键有效之后,会先判断有没有重按键标志,即是不是第一次检测到按键有效。假设第一次按下按键,检测到按键有效之后,设置了按键标志和重按键标志。当按键一直按着不放的时候,经过大约32ms之后,程序又会检测到第二次按键有效,由于此时有重按键标志,所以不会设置按键标志。因此当按键一直按下时,按键响应程序只响应一次。
通过对重按键标志的处理,还可以实现长按键的响应。这里就不详述了,留给大家去研究。本程序采用的是Sysstick定时中断,大家还可以采用其它中断来试试。
由于本人水平有限,程序有些地方还不是很完善,不足之处还请大家指正,让我们一起共同进步。
实验现象:
系统上电,LED灯亮,按下按键,LED灯灭,反复按键,LED灯在亮灭中切换。
5