堵塞式按键消抖
如下是一个最基本的堵塞式按键程序:
***it K1 = P1^0;
***it K1 = P1^1;
***it K1 = P1^2;
***it K1 = P1^3;
#define KEY_VALUE_NULL 0X00
#define KEY_VALUE_1 0X01
#define KEY_VALUE_1 0X02
#define KEY_VALUE_1 0X04
#define KEY_VALUE_1 0X08
void delay_ms(unsigned char xms)
{
unsigned char i,j;
for(i = xms;i > 0;i--){
for(j = 110;j > 0;j--);
}
}
unsigned char KeyScan(void)
{
unsigned char temp = KEY_VALUE_NULL;
if(K1 == 0){
delay_ms(20);
if(K1 == 0){
temp = KEY_VALUE_1;
}
}
if(K2 == 0){
delay_ms(20);
if(K1 == 0){
temp = KEY_VALUE_2;
}
}
if(K3 == 0){
delay_ms(20);
if(K1 == 0){
temp = KEY_VALUE_3;
}
}
if(K4 == 0){
delay_ms(20);
if(K1 == 0){
temp = KEY_VALUE_4;
}
}
return temp;
}
void main(void)
{
unsigned char keyValue = 0;
while(1)
{
keyValue = KeyScan();
if(keyValue == KEY_VALUE_1){
//按键1按下执行代码段
}
if(keyValue == KEY_VALUE_2){
//按键2按下执行代码段
}
if(keyValue == KEY_VALUE_3){
//按键3按下执行代码段
}
if(keyValue == KEY_VALUE_4){
//按键4按下执行代码段
}
}
}
该代码具有堵塞式按键的通病,那就是当按键按下后,所有的CPU时间都用来空跑,对于实时性高的任务,这20ms消抖会带来很多灾难性后果。20ms够我们跑很大量级的指令数了。我们怎么不使用delay来完成按键消抖呢?
时基法编程之按键消抖
如下是一个最基本的非堵塞式按键程序:
***it K1 = P1^0;
***it K1 = P1^1;
***it K1 = P1^2;
***it K1 = P1^3;
#define KEY_VALUE_NULL 0X00
#define KEY_VALUE_1 0X01
#define KEY_VALUE_1 0X02
#define KEY_VALUE_1 0X04
#define KEY_VALUE_1 0X08
unsigned char keyValue = 0;//按键键值接口
unsigned char keyScan1ms = 0;//按键时基驱动接口
//读取按键IO口电平
unsigned char KeyScan(void)
{
unsigned char temp = KEY_VALUE_NULL;
if(K1 == 0){
temp = KEY_VALUE_1;
}
if(K2 == 0){
temp = KEY_VALUE_2;
}
if(K3 == 0){
temp = KEY_VALUE_3;
}
if(K4 == 0){
temp = KEY_VALUE_4;
}
return temp;
}
void keyProcess(void)
{
static unsigned char keyLastValue = KEY_VALUE_NULL;//上次键值
static unsigned char keyNowValue = KEY_VALUE_NULL;//当前键值
static unsigned char keyFilterCnt = 0;//消抖计数器
//时基法编程核心语句
if(keyScan1ms < 10)return;//按键扫描时基未到10ms,则退出
keyScan1ms = 0;//千万不能忘记清零时基
keyNowValue = KeyScan();//读取此时IO口电平
if(keyNowValue != KEY_VALUE_NULL){//按键被按下
if(keyNowValue != keyLastValue){//此次按键跟上次按键键值不一样
keyFilterCnt = 0;
}
keyFilterCnt++;//消抖核心语句
}
else{//按键松开
//10ms采样一次,松手之前连续3次以上采样到按键按下。
if(keyFilterCnt > 3){
keyValue = keyLastValue;
}
keyFilterCnt = 0;//清消抖计数器
}
keyLastValue = keyNowValue;
}
void main(void)
{
//定时器初始化....
while(1)
{
keyProcess();
if(keyValue == KEY_VALUE_1){
keyValue = 0;//使用后手动清键值
//按键1被按下执行代码
}
//......
//其它进程...
}
}
//定时器中断1ms
void Timer0_Interrupt() interrupt 1
{
keyScan1ms ++;
}
上面代码是一个最基本的非堵塞式按键,仅仅实现按键消抖,但其有非常好的扩展性,诸如组合按键、长按、单双击都可以按照这种方式实现。在此不做细述,留待读者深入体会。
非堵塞式编程的优点是非常显然的,比如将前面文章的流水灯+蜂鸣器鸣叫+LED闪烁等等进程添加进来,程序不会有任何卡顿现象出现。但如果用堵塞式编程,则程序会出现明显的卡顿现象。
但是堵塞式也并不是无可取之处,因其逻辑简单、稳定,它在处理实时性要求不高的场合非常适用。