按键输入检测是单片机系统最常用的功能之一,检测方法常用的有:
1:主函数main的while(1)不断检测。这种方法因为加入了延时delay_ms(10); 使得同在while(1)中的其他程序得不到及时的处理,效率极低
2:中断方式。将按键的检测放到中断中,将检测后的结果放到while(1)中执行,这种方法效率极高,不耽误定时器中断的其他操作,我用这种方法好几年了,适合各种复杂或者简单的系统。
3:外部中断方式。在功能较少,外部中断利用率低的情况下,也是不错的选择,但在复杂系统,就不推荐了,因为占用了极其重要的外部中断资源,如果需要按键检测的优先级非常高,也可以使用。
分析这几种检测方式,我推荐方式2,
方式1和方式2对比
方式1:常规方法-原子例程
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键按松开标志
if(mode)key_up=1; //支持连按
if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
return 0;// 无按键按下
}
int main(void)
{
vu8 key=0;
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init(); //初始化与按键连接的硬件接口
LED0=0; //先点亮红灯
while(1)
{
key=KEY_Scan(0); //得到键值
if(key)
{
switch(key)
{
case WKUP_PRES:
LED0=!LED0;
break;
case KEY1_PRES:
LED1=!LED1;
break;
case KEY0_PRES:
LED0=!LED0;
LED1=!LED1;
break;
}
}else delay_ms(10);
}
}
因为延时的存在,这种方法局限性太强,除非用RTOS系统,否则在复杂的裸机环境中不太适用
方式2:中断方式检测--(具体细节请下载看例程)
key.c
void KEY_Interrupt_WK_UP(void)
{
static u8 fd=0;
static u8 cg=0;
static u8 degrees=1;
static u8 klj=0;
static u8 long_press=0;
static u8 er=0;
if(WK_UP==1)
{
if(!cg)
{
fd++;
if(fd==4) klj=1;
}
if(fd>60)
{
cg=1;
fd=0;
long_press=1;
er=1;
}
if(er)
{
//可按下时同步操作,不用释放时才有效果 ,只能执行一次,除非是cg还是0
}
}
else
{
if(klj)
{
if(long_press)//长按
{
long_press=0;
degrees=3;
key_wkup=degrees;
er=0;
}
else//短按
{
++degrees;
if(degrees>=3) degrees=1;
key_wkup=degrees;
}
fd=0;
cg=0;
klj=0;
}
else fd=0;
}
}
void KEY_Interrupt_MID(void)
{
static u8 fd0=0;
static u8 cg0=0;
static u8 klj0=0;
if(MID==0)
{
if(!cg0)
{
fd0++;
if(fd0==4) klj0=1;
}
}
else
{
if(klj0)
{
key_mid=1;
fd0=0;
cg0=0;
klj0=0;
}
else fd0=0;
}
}
time.c
void TIM6_IRQHandler(void) //TIM6中断
{
static u16 time_add=0;
static u16 time_design=2;
static u8 beep_change_state=1;
u16 sfdb=0;
if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
time_start=1;
KEY_Interrupt_WK_UP();//
KEY_Interrupt_MID();
}
}
main.c
#include "sys.h"
#include "delay.h"
#include "key.h"
#include "timer.h"
void KEY_Result_deal(void)//只能放到每次检测完按键的后面执行,太前面的话
{
u8 i=0;
if(key_wkup==1)//正常态
{
key_wkup=0;
//可加任务或命令 LED0=!LED0;
}
else if(key_wkup==2)//按下
{
key_wkup=0;
//可加任务或命令
}
else if(key_wkup==3)//长按
{
key_wkup=0;
//可加任务或命令
}
if(key_mid==1)
{
key_mid=0;
//可加任务或命令
}
}
int main(void)
{
u8 hjk=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
KEY_Init(); //初始化与按键连接的硬件接口
TIM6_Int_Init(999,719);//10Khz的计数频率,计数到10ms
while(1)
{
if(time_start==1)
{
switch(time_js)
{
case 0:
;
break;
case 1:
;
break;
case 2:
;
break;
case 3:
;
break;
case 4:
hjk++;
if(hjk>=2) //100ms
{
hjk=0;
KEY_Result_deal();
}
break;
deault:break;
}
time_start=0;
}
}
}
具体细节请下载附件,仅供参考,不当之处多指教!
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
一周热门 更多>