介绍
我们使用的按键都有按键抖动,当按下按键和松开按键都会有20ms的抖动,如果不处理这40ms的抖动,很影响单片机正常读取数据,平时我们都用while循环死等这40ms的抖动,在这40ms内单片机不会运行其他程序,这样很浪费单片机性能,在那些实时性要求不高的项目用while消抖不会影响程序正常运行,但在那些要求实时性很高的项目用while消抖显然不行,所以出现了中断扫描消抖
中断扫描消抖原理
我们用一个每1ms进入一次中断的定时器来进行按键消抖,我们用软件实现在中断中每20ms判断一次按键的状态是否改变,如果改变就进行相应的操作
单击,双击,长按原理
当检查到按键按下,我们开始计时(长按时间阈值),并等待按键松开,如果按键到我们规定的(长按时间阈值)时间都没有松开,这时就判断为长按,如果按键到我们规定的(长按时间阈值)时间之前松开按键时这时就有两种可能
- 单击
- 双击
单击:当按键到我们规定的(长按时间阈值)时间之前松开按键时,我们继续计时(双击时间阈值),当按键到我们规定的(双击时间阈值)时间都没有按下时,这时我们判断按键为单击 ,当按键到我们规定的(双击时间阈值)时间按下时我们判断按键为双击,
代码思维
代码
#include "KEY.h"
static uint8_t KEY_Flag=0;
uint8_t KEY_Check(uint8_t flag)
{
if(KEY_Flag&flag)
{
if (flag!=KEY_HOLD)
{
KEY_Flag&=~flag;
}
return 1;
}
return 0;
}
uint8_t KEY_State(void)
{
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==KEY_OK)
{
return KEY_OK;
}
else
{
return KEY_NO;
}
}
void TIM_Tick(void)
{
static uint8_t Count;
static uint8_t CurrState=KEY_NO,PrevState=KEY_NO;
static uint8_t S;
static uint16_t NUM;
if (NUM>0)
{
NUM--;
}
Count++;
if(Count>=20)
{
Count=0;
PrevState=CurrState;
CurrState=KEY_State();
//一直按住
if(CurrState==KEY_OK)
{
KEY_Flag|=KEY_HOLD;
}
else
{
KEY_Flag&=~KEY_HOLD;
}
//按下瞬间
if(CurrState==KEY_OK&&PrevState==KEY_NO)
{
KEY_Flag|=KEY_DOWN;
}
//松开瞬间
if(CurrState==KEY_NO&&PrevState==KEY_OK)
{
KEY_Flag|=KEY_UP;
}
switch (S)
{
case 0:
//判断按键是否按下
if(CurrState==KEY_OK)
{
//按下S置1
S=1;
//并开始记时间,如果2秒后按键还没有松开,按键长按
NUM=KEY_TIME_LONG;
}
break;
case 1:
//按键松开
if(CurrState==KEY_NO)
{
//S置2
S=2;
//此时按键已经松开,不可能是长按,记时,如果在200ms内再次按下,就是双击
NUM=KEY_TIME_DOUBLE;
}
//按键未松开
else if (NUM==0)
{
//S置4
S=4;
//计时判断是一直长按还是普通长按,如果在100ms后还没松开就是一直长按
NUM=KEY_TIME_LONGLONG;
}
break;
case 2:
//按键按下,双击
if(CurrState==KEY_OK)
{
//双击,S置3,在S=3中将S置0
KEY_Flag|=KEY_DOUBLE;
S=3;
}
//按键未按下,单击
else if(NUM==0)
{
//单击,将S置0
KEY_Flag|=KEY_SINGLE;
S=0;
}
break;
case 3:
//双击,将S置0
if(CurrState==KEY_NO)
{
S=0;
}
break;
case 4:
//按键松开,长按
if(CurrState==KEY_NO)
{
//长按
KEY_Flag|=KEY_LONG;
S=0;
}
//按键未松开,一直长按,
else if (NUM==0)
{
//一直长按
KEY_Flag|=KEY_LONG_LONG;
}
break;
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim2)
{
TIM_Tick();
}
}
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"
#include "tim.h"
#define KEY_OK 0
#define KEY_NO 1
//按住不放
#define KEY_HOLD 0X01
//按下瞬间
#define KEY_DOWN 0X02
//松开瞬间
#define KEY_UP 0X04
//单击
#define KEY_SINGLE 0X08
//双击
#define KEY_DOUBLE 0X10
//长按
#define KEY_LONG 0X20
//一直长按
#define KEY_LONG_LONG 0X40
#define KEY_TIME_DOUBLE 200
#define KEY_TIME_LONG 1000
#define KEY_TIME_LONGLONG 100
uint8_t KEY_State(void);
uint8_t KEY_Check(uint8_t flag);
#endif

