[转自:http://www.52rd.com/Blog/Detail_RD.Blog_cambrain_24794.html]
程序一:
unsigned char Trg; //全局变量
unsigned char Cont; //全局变量
void KeyRead(void) //判断按键状态的子程序
{
unsigned char ReadData=P0^0xFF;
Trg=ReadData&(ReadData^Cont);
Cont=ReadData;
}
P0口上拉电阻连接,并且通过一个开关接到地,按键检测即检测低电平。
分析:由于在按位与、或、非逻辑运算中单独的某一位的运算与其他各位无关,所以分析时只取P00,那么上面的程序就可以变成下面的形式:
程序二:
bit Trg; //全局位变量
bit Cont; //全局位变量
void KeyRead(void) //判断按键状态的子程序
{
bit ReadData=P00^1;
Trg=ReadData&(ReadData^Cont);
Cont=ReadData;
}
①按键未被按下,P00=1,经分析得:
ReadData=0;Trg=0;Cont=0。
②按键第一次被按下,P00=0,经分析得:
ReadData=1;Trg=1;Cont=1。
③按键被按住不放,P00=0,经分析得:
ReadData=1;Trg=0;Cont=1。
④按键被松开,P00=1,经分析得:
ReadData=0;Trg=0;Cont=0。(和按键未被按下时一样)
可以看到,按键被按下的不同状态即阶段就对应不同的Trg和Cont,这样处理按键就简单了。
如果希望按键短按一下有效,长按无效,则检测Trg的值;如果希望按键长按有效,则检测Cont的值,如果Cont一直为1,则说明按键被一直按下。
如果是检测多个按键的话就采用程序一的形式。比如:要检测P0口的8个按键,如果P01被第一次按下,那么ReadData=0x02;Trg=0x02;Cont=0x02。如果P07被长按下,那么ReadData=0x80;Trg=0x00;Cont=0x80。这样只要知道Trg和Cont的值就可以知道哪个键被按下以及被按下的状态和阶段。
另外还有一个按键消抖的问题,我采用的是定时器中断,每隔20ms进入中断检测按键,如果这一次的检测结果和上一次的一样的话,就进入上面的程序一判断按键状态。如下:(检测P01)
unsigned char Trg;
unsigned char Cont;
void main (void0
{
//初始化//
if(Trg&0x02) ///按键被第一次按下
{
//程序处理//
}
}
void Timer1(void) interrupt 1
{
unsigned char ReadData;
unsigned char P0value_present;
static unsigned char P0value_last=0;
//关中断等//
P0value_present=P0; //端口当前值
if(P0value_present&P0value_last)
{
ReadData=P0value_present^0xFF;
Trg=ReadData&(ReadData^Cont);
Cont=ReadData;
}
P0value_last=P0; //端口上一次的值
//开中断等//
}