一般独立按键检测方法

通常,按键一边连接着GPIO口,一边连接着GND,当按键被按下时,GPIO口的电平被拉低,当检测到低电平就可以认为按键被按下。

但是这种方法有一点缺陷:按键被按下和松开的5~10ms电平是不稳定的,电平会忽高忽低,造成连续按下按键的假象。

一般,为了解决这个问题,有两种办法,一种是硬件消抖,在按键两端加一个电容,由于电容的电压不能突变而是平缓变化,这就帮助按键的电压不能突变,即按下按键,电压就从高电平到低电平;松开按键,就从低电平到高电平(非自锁按键)。

还有有一种办法是软件消抖,利用if语句实现

if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET)
{
    HAL_Delay(10);
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET)
    {
        //实现程序
    }
     }

这是利用hal库实现的语句,HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET的意思GPIOB端口组的0端口电平等于高电平的意思

如果它等于高电平,那么利用HAL_Delay(10);延迟10ms等按键电平抖动结束再检测电平,就可以跳过中间那段忽上忽下的电平抖动了。

但是这有个缺点,那就是HAL_Delay(10);延迟10ms检测,这就造成了程序执行到这里的时候会在这里停留10ms再继续执行下一步,造成了整个程序执行的滞留、阻塞,这是不希望看见的。

例如一个屏幕如果是10ms刷新一次,如果再阻塞10ms就变成了20ms刷新一次,再加上更多的程序,要求即时性的,例如舵机变化。如果这些程序也要等上10ms,那肯定是个不理想的情况。

无阻塞按键检测方法

无阻塞按键检测是利用定时器检测按键。

开启定时器中断,每10ms会执行一次按键检测。若检测到一次按键GPIO口变为低电平,那么可能是按键被按下,先给个让一个变量times变为1,然后执行主程序,不管按键变化。又一个10ms后,定时器中断再次执行按键检测,发现按键GPIO口还是低电平,即代表按键被按键了。

从以上的方法可以发现,HAL_Delay(10);延迟程序被定时器中断完美解决了。中间的10ms不再是单纯的停滞,而是交给定时器专门去数数,主程序还是在执行程序,10ms后再检测按键GPIO口的电平,也可以跳过中间的10ms电平抖动。

以下是hal库的实现方法,仅供参考

uint8_t key_read()
{
if(!(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)))      return 1;
else if(!(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1))) return 2;
else if(!(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2))) return 3;
else if(!(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))) return 4;
else return 0;
}

//下面的的数组1-5代表的是按键的键值,结构体里的age是低电平的次数,short_flag=1代表检测到按下

void Key_serv()
{
uint8_t key_sta=key_read();
if(key_sta!=0)
{
    bkey[key_sta].age++;                               
    if(bkey[key_sta].age==2)bkey[key_sta].short_flag=1;
}
else
{
    for(int i=0;i < 5;i++) bkey[i].age=0;
}    
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //定时器中断
{
if(htim->Instance==TIM6)
{
    Key_serv(); 
}


}
最后修改:2025 年 01 月 11 日