机械开关在人按下开关或松开开关的瞬间,开关内部金属圆盘与触点之间会发生抖动,如果程序频繁扫描按键,可能会误判为多个按键动作,不利于程序的正常运行。因此在对机械按键进行检测时通常需要进行消抖。
常见的消抖方式包括使用RS锁存器或电容的硬件消抖以及软件消抖,其中软件消抖是最常用的消抖方式。通过软件消抖的过程如图1所示,微控制器以某一固定时间间隔扫描独立按键,避免按键抖动时段的多次采样,进而避免错误检测到多个按键动作的问题。
图1
定时采样可以通过微控制器的定时中断来实现。
使用STC89C52RC单片机,外部时钟12Mhz,对6个独立按键进行扫描步骤如下:
- 初始化定时器
#include <REGX52.H>
void Timer0_Init()
{
TMOD |= 0X01; //MO置1
TMOD &= 0XF1; //M1 Gate C/T置零
TH0 = 0XFC; //1毫秒计数初值高8位
TL0 = 0X18; //低8位
EA = 1; //打开总中断
ET0 = 1; //打开计数器0中断
//优先级默认为最低级0
TR0 = 1; //定时器开始运行
}
- 定义按键扫描程序
#include <REGX52.H>
//独立按键
#define Button1 P0_0
#define Button2 P0_1
#define Button3 P0_2
#define Button4 P0_3
#define Button5 P0_4
#define Button6 P0_5
/**********************************************************
* @order : 01
* @brief : 扫描独立按键,检测按键松手瞬间
* @param : 无
* @retval : Num = 检测到的键值,可能值包括
0 —— 没有按键按下
1-6 —— 键值
************************************************************/
unsigned char ScanIndepButton()
{
static unsigned char lastNum = 0, nowNum = 0;
unsigned char num = 0;
if(Button1 == 0){num = 1;}
else if(Button2 == 0){num = 2;}
else if(Button3 == 0){num = 3;}
else if(Button4 == 0){num = 4;}
else if(Button5 == 0){num = 5;}
else if(Button6 == 0){num = 6;}
else{num = 0;}
//边沿判断
lastNum = nowNum;
nowNum = num;
num = 0;
if(lastNum != 0 && nowNum == 0) //监测按键松手的瞬间
{
num = lastNum;
}
return num;
}
- 在中断函数中调用按键扫描程序
/**********************************************************
* @order : 02
* @brief : 定时器0中断函数,每隔1ms执行该函数
* @parameter : 无
* @retval : 无
************************************************************/
void Timer0_Routine(void) interrupt 1
{
static unsigned int count = 0;
TH0 = 0XFC;
TL0 = 0X18;
count++;
if(count >= 15) //每隔15ms扫描键盘
{
KeyNum = ScanIndepButton();
count = 0;
}
}