目录
当按键按下的时候是有电平抖动的,所以有以下三种解决方案
一,使用delay直接大致跳过抖动的那段周期
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
二,找两个按键电平降低 前后时刻的电位
较为简单,不做示例
三,多次采样 使用数组和char型变量存放判断
按键扫描函数
单个按键扫描函数
通过判断第i个数组的数值来判断i对应的按键是否被按下
//单个按键扫描函数
unsigned char key_scan()
{
unsigned char i;
unsigned char key_value=0;
static unsigned char pre_sta[2]={1,1};
for(i=0;i<2;i++)//2代表能扫描两个按键
{
if(cur_sta[i]!=pre_sta[i])
{
if(pre_sta[i])
{
key_value=i+1;// 按键值
}
pre_sta[i]=cur_sta[i];// 更新前一个数组的状态
}
}
return(key_value);
}
双按键按下的扫描函数
思路:当进入第二个按键的判定时,倘若第一个按键正处于按下的状态,则视为两个按键同时按下,倘若此时第一个按键并不是按下的状态,则正常判断按键按下。
简单来说就是类似于ctrl+c/v的操作逻辑
unsigned char key_scan()
{
char i;
char key_value=0;
//判断两个按键是否同时按下
for(i=0;i<2;i++)
{
if(pre_sta[i]!=cur_sta[i])
{
if(pre_sta[i])
{
if(i==1 && cur_sta[0]==0) //当第二个按键按下时,第一个按键也正好处于按下状态
key_value=3;
else
{
key_value=i+1;
}
}
pre_sta[i]=cur_sta[i];// 状态更新
}
}
return(key_value);
}
通过定时器的控制即可实现另一种双按键判定
#include <REGX52.H>
#include "Timer0.h"
#define X 2 //X按键双击
static unsigned char currentkeynum;
static unsigned char lastkeynum;
static unsigned int lasttime=0;
static unsigned int currenttime=0;
static unsigned int timecounter;
void doubleclick_init(void)//初始化双击判断
{
lastkeynum=0;
lasttime=0;
Timer0_Init();//初始化定时器
}
unsigned char check(unsigned char currentkeynum)
{
if(currentkeynum==X && lastkeynum!=X)//判断第一次按按键
{
lasttime=timecounter;
lastkeynum=currentkeynum;
return 0;//提前返回,第二次输入按键再重新处理
}
if(lastkeynum==X && currentkeynum==X)//判断第二次按按键
{
currenttime=timecounter;
if(currenttime-lasttime>0 && currenttime-lasttime<1000)//判断两次按键的时间间隔是否为连击
{
lastkeynum=0;//重置上次键值
return 1;//满足双击条件
}
else//不满足连续两次按按键就重新初始化
{
lastkeynum=0;
lasttime=0;
}
}
return 0;
}
void Timer0_Routine() interrupt 1
{
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
timecounter++;
if(timecounter>=10000)
{
timecounter=0;
}
}
按键动作函数
一般要根据实际场景进行定制使用
void key_action(unsigned char key_value)
按键更新函数
根据按键个数进行相应的调整
两个按键的按键更新
void cur_sta_update()
{
unsigned char i;
static unsigned char buff[2]={0xff,0xff};
//八次更新状态,要是按键对应的八位都为1则是按下
buff[0]=(buff[0]<<1)|k1;
buff[1]=(buff[1]<<1)|k2;
//遍历两个按键
for(i=0;i<2;i++)
{
if(buff[i]==0xff)
cur_sta[i]=1;
else if(buff[i]==0x00)
cur_sta[i]=0;
}
}
三个按键的按键更新
void cur_sta_update()
{
char i;
static unsigned char keybuff[3]={0xff,0xff,0xff};
//八次更新状态,要是按键对应的八位都为1则是按下
keybuff[0]=(keybuff[0]<<1)|k1;
keybuff[1]=(keybuff[1]<<1)|k2;
keybuff[2]=(keybuff[2]<<1)|k3;
//遍历三个按键
for(i=0;i<3;i++)
{
if(keybuff[i]==0xff)
cur_sta[i]=1;
else if(keybuff[i]==0x00)
cur_sta[i]=0;
}
}
按键的定时器
void timer_2ms() interrupt 1
{
static unsigned int sec_count=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
sec_count++;
if(Turn_on)
{
if(sec_count==500) //1 sec
{
sec_count=0;
DisplayCode_update_time();
}
}
cur_sta_update();
}
结语
按键的扫描和判定都可以直接封装成函数,难点在于key_action函数怎么写,怎么去根据实际的任务需求去调整代码逻辑和时序安排