/*--------------------------------参考资料:新手入门之按键编------------------------
===作者:Warden===
===Email:[email protected] 欢迎与我进行交流===
===更多资料整理:http://blog.ednchina.com/warden/===
===编写目的:希望借以此编能给予未入门及刚入门的朋友作参考==
********************如未标明出处则为作者原创************************
*/
//////////////////////////////////////////////////////方法1////////////////////////////////////////////
//按键触发方式:低电平触发
//最简单的按键 此处按P3的高四位
//这种方式简单,但实用性不高,原因是没有人希望看到当你一直按住一个按键时程序是在一个地方不动,其次程序没有进行去抖,在实际中基本上没有应用价值
unsigned char key_scan(void)
{
unsigned char temp=0,key_value=0;
temp=P3&0xf0;
if(temp!=0xf0)//如果p3高四位检测到低电平
{
if(temp==0x70)//高位按下
key_value=1;
else if(temp==0xb0)//第六位按下
key_value=2;
else if(temp==0xd0)//第五位按下
key_value=3;
else if(temp==0xe0)//第四位按下
key_value=4;
else
key_value=0;
}
while((P3&0xf0)!=0xf0)
;//等待按键释放,避免多次触发
return key_value;//返回按键值
}
--------------------------------------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////方法2////////////////////////////////////////////
//按键触发方式:低电平触发
//采用软件延时去抖,实用性也不高,只适合对实时性要求不高的场合
//软件延时10ms程序
// *******************************************************
void delay_nms(void)
{
unsigned int i=8000;
while(i--)
; //程序略,不同mcu和不同晶振都会产生不同的软件延时结果
}
unsigned char key_scan(void)
{
unsigned char temp=0,key_value=0;
temp=P3;
if((temp&0xf0)!=0xf0)//如果p3高四位检测到低电平
{
delay_nms();//软件延时10ms去抖
{
temp=P3&0xf0;
if(temp!=0xf0)//再次检测如果p3高四位检测到低电平
{
if(temp==0x70)//高位按下
key_value=1;
else if(temp==0xb0)//第六位按下
key_value=2;
else if(temp==0xd0)//第五位按下
key_value=3;
else if(temp==0xe0)//第四位按下
key_value=4;
else
key_value=0;
}
}
}
return key_value;//返回按键值
}
/*
注意:
1)局部变量(本例中temp和temp_value)必须在定义时对其进行赋值!
2)本例中delay_nms()可用软件仿真来参看其运行时间,本例中,当晶振为12M时,i=1000时,定时约为9ms;i=8000时,定时约为72ms,软件仿真时请务必设置好晶振大小!本例使用keil c51 12分频
3)实例每次按键低电平脉宽有几十个ms,(依按键长短而定),假如某次按键为30ms,为避免多次触发,所以用i=8000,去抖72ms,来延长按键去抖时间;
*/
--------------------------------------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////方法3////////////////////////////////////////////
//按键触发方式:低电平触发
//此法为作者常用按键扫描程序,自认为实用性较高,条理比较清晰,易懂
//按键扫描函数......接口在此修改,这里接3.4~3.7
unsigned char key_scan(void)
{
unsigned char temp=0;
if((P3&0xf8)!=0xf8)
{
temp=P3&0xf8;
if(temp==0xe8)//---------------------------p3.4按下
return 1;//1
else if(temp==0xd8)//----------------------p3.5按下
return 3;//2
else if(temp==0xb8)//----------------------p3.6按下
return 2;//3
else if(temp==0x78)//----------------------p3.7按下
return 4;//4
else if(temp==0xf0)//----------------------p3.3按下
return 5;//4
}
return 0;
}
unsigned char mark_10ms;//按键计数器,只要将"mark_10ms++;"其放在定时中断中;(我一般采用10ms定时中断);注:定时中断可放入其他程序;
//考虑到一般工程都会用到定时器,所有就将"按键计数器"放入中断中来检测时间
//另一种模式:定义成unsigned int 型,在主程序内进行周期循环计数,此方法只适合主函数执行时间相差不大的情况
unsigned char key_flag;//当确定有按键按下时置1
void key_program_work(void)
{
// 上次键值 初始值为0 按键阶段
static unsigned char last_key_value=0, key_status=1;
// 临时键值,记录每次扫描的键值,如果有键按下则其值不为0
unsigned char key_value_temp=0;
key_value_temp=key_scan();
switch(key_status)
{
case 1://阶段1:开始阶段
//如果有键按下key_value_temp不为0
if( key_value_temp)
{
key_status=2;//一检测到有键按下,则进入下一阶段
mark_10ms=0;//清按键计数器
}
break;
case 2://阶段2:去抖时间检测
// 如果本次有按键值且上次也有按键按下时
if((last_key_value==key_value_temp) && key_value_temp)
{
if(mark_10ms>=2)//去拌时间>=2*10ms
{
key_value=key_value_temp;//单键已按下
key_status=3;//进入下一阶段,以便检测是否有长按
key_flag=1;//确认按键已经按下-------------------
}
}
else//是抖动,还回阶段1
key_status=1;
break;
case 3://阶段3:长按检测
if((last_key_value==key_value_temp) && key_value_temp)
{
if(mark_10ms==251)//如果不加此句长按触发为mark_10ms=240,0,20....加此句可使长按触发时间间隔相等
mark_10ms=50;
if(mark_10ms>40 && mark_10ms%20==0 )//-----长按触发时间间隔:20*(10-1)ms,可在此修改其间隔
{
mark_10ms++;//此句必加-------避免:假如mark_10ms=20时,主函数10ms内可能执行N次循环,此时mark_10ms还没到21,因此在这加1避免在mark_10ms=20时只触发一次按键--
key_value=key_value_temp;
key_flag=1;//长按时,确认按键已经按下-------------------
}
}
else//无长按,进入阶段1
key_status=1;
break;
}
last_key_value=key_value_temp;//保存本次键值
}
//备注:亦可将上函数全部放入中断,而不放在主函数中,效果一样;
评论0