短按和长按其实都是同一种思路,区别就是延时触发的延迟时间长短不同。
所以,这里的关键就是,如何合理地检测低电平持续的时间。
短按,其实可以理解为单击,就是按下之后要很快松开,因为时间长了会被判定为长按。
一开始,我的想法是,检测是否有低电平发生,如果有,就再延时一段时间比如5s,之后再次判断是否还是低电平,如果是,则表示发生了长按。可是,一细想,又发现这个思路有BUG,如果我先按下按键,然后松开,等到快5秒的时候再按下,这样,也会两次都检测到低电平,但实际并不是长按。
我又想,那么在5秒内,一直判断是不是低电平不就行了,所以,需要造一个5秒的for循环,在里面一直判断是不是低电平,只要有一个高电平发生,就不能判定为长按,而是被判定为短按。
static void KEY_Detect()
{
uint8_t i = 0;
if(KEY1.KEY_Flag == TRUE)//先判断有按键按下
{
KEY1.Click = FALSE;
KEY1.Press = TRUE;
//触摸按键长按检测
for(i=0;i<500;i++)
{
HAL_Delay(10);
//如果5s内,按键状态出现高电平,此时按键为短按,跳出循环
if(检测到高电平)
{
KEY1.Click = TRUE;
KEY1.Press = FALSE;
break; //跳出for循环
}
}
if(是短按)
{
//短按对应的动作
}
if(是长按)
{
//长按对应的动作
}
//清除按键状态
KEY1.KEY_Flag = FALSE;
KEY1.Click = FALSE;
KEY1.Press = FALSE;
}
}
这种思路是可行的,但是根据for循环来实现按键时长,并不精准。
如果想要更精准的时间判断,怎么办呢?
最好是结合定时器。
定时器的思路其实和上述for循环是一样的。
也是每隔10ms判断一次按键状态,只是定时器方式是将这个判断放到定时器中了。
可以让其在10ms定时器里进入判断500次,只要没有高电平出现,就置位长按标志,否则置位短按标志。
之后再根据这个标志去执行相应动作即可。
又或者在定时器里面判断低电平来计数,只要计数大于等于500,就可以执行相应动作。
比如:
static int cnt=0;
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
cnt++;
if(cnt>500)
{
PRINT("long press\n");
……
cnt =0;
}
……
}
注意,编程时,不一定非要根据某种动作来执行另一种动作,可以先根据一种动作来设置一些相应的标志位,然后在其他地方根据标志位再进行一些动作,这样更加灵活。