void key_scan_task(uint8_t key_pin) {
uint32_t timer_cnt = 0, countdown = 0;
uint32_t click_cnt = 0;// 短按次数
bool long_press = false;
// 10ms定时扫描
#define JITTER_CNT 5 // 抖动时间,大约50ms
#define LONG_PRESS_CNT 100 // 长按检测时间,长按不参与前后连击检测
#define COUNTDOWN_INIT 20 // 连击检测倒计时
bflb_gpio_init(gpio, key_pin, GPIO_INPUT | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_0);
while(1) {
if(bflb_gpio_read(gpio, key_pin)) {// 高电平时计数
if(timer_cnt < 10000000) timer_cnt++;// 避免一直长按时溢出
}
else {// 低电平时判断状态
if(countdown > 0) countdown--;// 倒计时
if(timer_cnt >= LONG_PRESS_CNT) long_press = true;
else if(timer_cnt >= JITTER_CNT) {
click_cnt++;
countdown = COUNTDOWN_INIT;// 重新倒计时
}
// 状态输出
if(long_press) {// 长按
printf("long_press:%d\r\n", timer_cnt);
long_press = false;
click_cnt = countdown = 0;// 重置,丢弃前面的连击
}
else if(click_cnt > 0 && countdown == 0) {// 点击1次或多次
printf("%d click\r\n", click_cnt);
click_cnt = 0;
}
// else {} // 未按键,抖动,连击检测倒计时未结束
timer_cnt = 0;// 重置
}
vTaskDelay(10);
}
}
定时扫描GPIO的电平,统计高电平的持续时间,如果超过特定值则为长按,小于特定值为按键抖动,介于两个特定值之间为短按,短按后开启倒计时,在指定时间内再次短按,判断为连击
利用M61-32板子上的烧录键进行测试
xTaskCreate(key_scan_task, "key_scan_task", 1024, GPIO_PIN_2, 16, &key_scan_task_hd);
![image.png image.png](data/attachment/forum/202401/13/223717bj9e282n4qc5ae28.png)
|