按键防抖
自复位按键,在按下与弹起的时候,会有机械震荡产生,一般是毫秒级,所以高频的CPU采集数据时,会出现一次按键操作,识别为多次,造成按键多次触发的情况。
所以需要进行按键防抖操作。
按键防抖分软件防抖和硬件防抖。
硬件防抖
硬件防抖是就是在按钮上并上一个合适大小的电容(100nF),用来削峰。
软件防抖
延时防抖
不推荐
首先了解按键的抖动时间,然后采用延时的方式规避这个时间,简单易懂。
高频处理的业务中,会阻塞CPU,导致其他的代码执行效率低。
uint8_t KeyNum = 0;
if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET)
{
Delay_ms(10);
while(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET);
Delay_ms(10);
KeyNum = 1;
}
优点:代码简单
缺点:阻塞CPU
状态机 + 计数防抖
采用计数的方式,可以有效避免CPU的阻塞。
状态机的引入,可以有效管理按键的状态,避免误识别。
状态机流程:
0:初始 <-> 1:触发(抖动) -> 2:稳定 <-> 3:离开(抖动) -> 0:初始
注意抖动时期可以跳到上一个状态,也可以待其稳定(采用计数方式判断)切到下一个状态。
这里先按一个按键写代码:
uint16_t Key1_Cnt = 0; // 计数
uint8_t Key1_Sta = 0; // 状态
/**
* @brief 扫描按键1的状态
* @param 无
* @retval 无
*/
void Key_Scan0(void)
{
// 0:初始 1:触发 2:稳定 3:离开 0:初始
switch(Key1_Sta)
{
case 0:
if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET)
{
Key1_Sta = 1;
Key1_Cnt = 0;
}
break;
case 1:
Key1_Cnt++;
if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_SET)
{
Key1_Sta = 0;
} else if(Key1_Cnt == 10)
{
Key1_Sta = 2;
Key1_Cnt = 0;
Debug_Printf("key1 pressed");
}
break;
case 2:
if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_SET)
{
Key1_Sta = 3;
Key1_Cnt = 0;
}
break;
case 3:
Key1_Cnt++;
if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET)
{
Key1_Sta = 2;
} else if(Key1_Cnt == 10)
{
Key1_Sta = 0;
Debug_Printf("key2 released");
}
break;
default:
break;
}
}
如果是多个独立按键可以封装下代码:
#define KEY_NUM 2 // 按键个数
#define KEY_CNT 5 // 计数次数
uint16_t Key_Cnt[KEY_NUM + 1] = {0};
uint8_t Key_Sta[KEY_NUM + 1] = {0};
uint8_t Key_ReadPin(uint8_t n)
{
uint8_t sta = 0;
switch(n)
{
case 1:
sta = HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN);
break;
case 2:
sta = HAL_GPIO_ReadPin(KEY2_PORT, KEY2_PIN);
break;
default:
sta = -1;
break;
}
return (uint8_t)sta;
}
/**
* @brief 扫描所有独立按键的状态
* @param 无
* @retval 无
*/
void Key_Scan(void)
{
uint8_t i = 0;
for(i = 1 ; i <= KEY_NUM; i++)
{
// 0:初始 1:触发 2:稳定 3:离开 0:初始
switch(Key_Sta[i])
{
case 0:
if(Key_ReadPin(i) == GPIO_PIN_RESET)
{
Key_Sta[i] = 1;
Key_Cnt[i] = 0;
}
break;
case 1:
Key_Cnt[i]++;
if(Key_ReadPin(i) == GPIO_PIN_SET)
{
Key_Sta[i] = 0;
} else if(Key_Cnt[i] == KEY_CNT)
{
Key_Sta[i] = 2;
Key_Cnt[i] = 0;
Debug_Printf("key %d pressed",i);
}
break;
case 2:
if(Key_ReadPin(i) == GPIO_PIN_SET)
{
Key_Sta[i] = 3;
Key_Cnt[i] = 0;
}
break;
case 3:
Key_Cnt[i]++;
if(Key_ReadPin(i) == GPIO_PIN_RESET)
{
Key_Sta[i] = 2;
} else if(Key_Cnt[i] == KEY_CNT)
{
Key_Sta[i] = 0;
Debug_Printf("key %d released", i);
}
break;
}
}
}