使用stm32,修改key_read完成读取
按键之间互不干扰,如1长按过程中可以正常识别2的单击等
key.c
/*
* key.c key.h
*
* 基于按键跳变状态完成的按键单击、双击、长按的扫描
* 使用1ms自增的uwTick做时间判断
* 按键默认初始化,默认硬件消抖
*
* 使用说明:在循环或任务中调用key_proc 重写执行函数
*
* V1.0 2025.8.17
*/
#include "gpio.h"
#include "key.h"
/* 将KEY_TEST_PRINT置1开启按键状态打印 置0关闭 */
#define KEY_TEST_PRINT 0
#if KEY_TEST_PRINT
#include "user_uart.h"
#endif
typedef enum {
KEY_IDLE = 0, // 空闲
KEY_PRESS, // 按下中
KEY_WAIT_SECOND, // 等待第二次按下
KEY_PRESS_SECOND // 第二次按下中
} KeyStateEnum;
typedef struct {
KeyStateEnum state;
uint32_t t_down;
uint32_t t_up;
} KeyState;
static KeyState key[5]; // 对应5个按键
/*
* @brief 按键当前状态读取函数
*
* @param void
*
* @return 按键按下的状态 在8位变量上以1表示
*
* */
uint8_t key_read(void){
uint8_t key_val;
key_val = HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_12)<<0|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_10)<<1|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_8)<<2|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_7)<<3|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_13)<<4;
if(key_val != (HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_12)<<0|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_10)<<1|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_8)<<2|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_7)<<3|\
HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_13)<<4)){
key_val = 0x1f;
}
return key_val^0x1f;
}
/*
* @brief 检测按键跳变状态,触发单击 双击 长按执行函数
*
* @note 1.按键的默认最小扫描间隔为10ms
* 2.执行函数为弱定义,重写执行函数完成所需功能
* 3.因需要同时判断双击长按,单击的响应将会较慢,如有需要使用key_read进行直接判断
* 4.单机的判断为按下时长小于1s,松开后0.5s内没有操作触发
* 5.双击的判断为第一次按下小于1s,松开到第二次按下小于0.5s触发
* 6.长按的判断为第一次按下到松开大于1s触发
* 7.按键的判断优先级为:长按>双击>单击
*
* @param void
*
* @return void
*
* */
void key_proc(void){
static uint32_t uwTick_KEY;
if(uwTick - uwTick_KEY < 10) return; // 10ms扫描
uwTick_KEY = uwTick;
uint8_t val = key_read(); // 当前按键状态
for(int i=0;i<5;i++){
uint8_t mask = 1<<i;
KeyState *k = &key[i];
switch(k->state){
case KEY_IDLE: // 空闲 -> 第一次按下
if(val & mask){
k->t_down = uwTick;
k->state = KEY_PRESS;
}
break;
case KEY_PRESS: // 第一次按下中
if(!(val & mask)){ // 松开
k->t_up = uwTick;
uint32_t dt = k->t_up - k->t_down;
if(dt > 1000){ // 长按
key_click_long(mask);
k->state = KEY_IDLE;
}else{
k->state = KEY_WAIT_SECOND; // 等待双击
}
}
break;
case KEY_WAIT_SECOND: // 等待第二次
if(val & mask){ // 第二次按下
if(uwTick - k->t_up < 500){
k->t_down = uwTick;
k->state = KEY_PRESS_SECOND;
}else{ // 超时 -> 单击
key_click(mask);
k->state = KEY_PRESS; // 这次按下当作新的一次
k->t_down = uwTick;
}
}else if(uwTick - k->t_up >= 500){ // 超时未按 -> 单击
key_click(mask);
k->state = KEY_IDLE;
}
break;
case KEY_PRESS_SECOND: // 第二次按下中
if(!(val & mask)){ // 松开 -> 确认双击
key_click_double(mask);
k->state = KEY_IDLE;
}
break;
}//end switch
}//end for
}
__weak unsigned char key_click(unsigned char key_val){
#if KEY_TEST_PRINT
printf("key_click = %d\n",key_val);
#endif
return key_val;
}
__weak unsigned char key_click_double(unsigned char key_val){
#if KEY_TEST_PRINT
printf("key_click_double = %d\n",key_val);
#endif
return key_val;
}
__weak unsigned char key_click_long(unsigned char key_val){
#if KEY_TEST_PRINT
printf("key_click_long = %d\n",key_val);
#endif
return key_val;
}
key.h
#ifndef _KEY_H_
#define _KEY_H_
enum KEY_VAL{
KEY1 = 1,
KEY2 = 2,
KEY3 = 4,
KEY4 = 8,
KEY5 = 16
};
unsigned char key_read(void);
void key_proc(void);
unsigned char key_click(unsigned char key_val);
unsigned char key_click_double(unsigned char key_val);
unsigned char key_click_long(unsigned char key_val);
#endif

1万+

被折叠的 条评论
为什么被折叠?



