Files
stm32f407ve_black/BSP/Src/bsp_key.c
2026-01-29 15:08:30 +08:00

352 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : bsp_key.c
* @brief : 板级支持包按键驱动实现
******************************************************************************
*/
/* USER CODE END Header */
#include "bsp_key.h"
#include "bsp_config.h"
#include "hal_gpio.h"
#include "bsp_board.h"
#include "bsp_board_manager.h"
#include "hal_delay.h"
/**
* @brief 按键防抖配置
*/
#define KEY_DEBOUNCE_COUNT 5 /* Debounce count (each update is ~10ms, so 50ms debounce) */
#define KEY_LONG_PRESS_TIME 1000 /* Long press time in ms */
#define KEY_REPEAT_INTERVAL 200 /* Repeat interval in ms */
#define KEY_SHORT_PRESS_TIME 200 /* Short press time in ms */
#define KEY_UPDATE_INTERVAL 10 /* Update interval in ms */
/**
* @brief 按键配置结构体
*/
typedef struct {
hal_gpio_port_t port;
hal_gpio_pin_t pin;
uint8_t active_high;
} bsp_key_config_t;
/**
* @brief 按键状态结构体,用于防抖和事件检测
*/
typedef struct {
/* Debounce state */
bsp_key_state_t current_state; /* Current debounced state */
bsp_key_state_t previous_state; /* Previous debounced state */
uint8_t debounce_counter; /* Debounce counter */
/* Event flags */
uint8_t press_event; /* Press event flag */
uint8_t release_event; /* Release event flag */
uint8_t long_press_event; /* Long press event flag */
uint8_t repeat_event; /* Repeat event flag */
uint8_t short_press_event; /* Short press event flag */
/* Timing variables */
uint32_t press_start_time; /* Press start time in ms */
uint32_t last_repeat_time; /* Last repeat event time in ms */
uint32_t current_time; /* Current time in ms */
/* Configuration */
uint16_t long_press_time; /* Long press time in ms */
uint16_t repeat_interval; /* Repeat interval in ms */
uint16_t short_press_time; /* Short press time in ms */
/* Key configuration */
const bsp_button_config_t* button_config;
} bsp_key_internal_state_t;
/**
* @brief 按键状态表,用于防抖和事件检测
*/
static bsp_key_internal_state_t key_state_table[BSP_KEY_ID_MAX] = {0};
/**
* @brief 获取当前板卡按键配置
*/
static const bsp_button_config_t* bsp_key_get_button_config(bsp_key_id_t key_id) {
const bsp_board_config_t* board_config = bsp_board_get_config();
if (board_config && key_id < board_config->buttons.count) {
return &board_config->buttons.buttons[key_id];
}
return NULL;
}
/**
* @brief 读取原始按键状态(无防抖)
* @param key_id: 按键 ID
* @retval 原始按键状态
*/
static bsp_key_state_t bsp_key_read_raw(bsp_key_id_t key_id) {
bsp_key_state_t state;
const bsp_button_config_t* button_config = bsp_key_get_button_config(key_id);
if (button_config) {
hal_gpio_pin_state_t gpio_state;
/* Read GPIO pin state */
gpio_state = hal_gpio_read_pin(button_config->port, button_config->pin);
/* Convert to key state based on active level */
if (button_config->active_high) {
state = (gpio_state == HAL_GPIO_PIN_SET) ? BSP_KEY_STATE_PRESSED : BSP_KEY_STATE_RELEASED;
} else {
state = (gpio_state == HAL_GPIO_PIN_RESET) ? BSP_KEY_STATE_PRESSED : BSP_KEY_STATE_RELEASED;
}
} else {
state = BSP_KEY_STATE_RELEASED;
}
return state;
}
/**
* @brief 获取当前系统时间(毫秒)
* @retval 当前时间(毫秒)
*/
static uint32_t bsp_key_get_time_ms(void) {
/* Use HAL tick function */
return hal_get_tick();
}
/**
* @brief 初始化所有按键
*/
void bsp_key_init(void) {
uint8_t i;
/* Get current board configuration */
const bsp_board_config_t* board_config = bsp_board_get_config();
/* Initialize key state table */
for (i = 0; i < BSP_KEY_ID_MAX; i++) {
/* Get button configuration for this key */
const bsp_button_config_t* button_config = bsp_key_get_button_config((bsp_key_id_t)i);
/* Initialize with current state */
key_state_table[i].current_state = bsp_key_read_raw((bsp_key_id_t)i);
key_state_table[i].previous_state = key_state_table[i].current_state;
key_state_table[i].debounce_counter = 0;
/* Clear event flags */
key_state_table[i].press_event = 0;
key_state_table[i].release_event = 0;
key_state_table[i].long_press_event = 0;
key_state_table[i].repeat_event = 0;
key_state_table[i].short_press_event = 0;
/* Initialize timing variables */
key_state_table[i].press_start_time = 0;
key_state_table[i].last_repeat_time = 0;
key_state_table[i].current_time = 0;
/* Set default configuration */
key_state_table[i].long_press_time = KEY_LONG_PRESS_TIME;
key_state_table[i].repeat_interval = KEY_REPEAT_INTERVAL;
key_state_table[i].short_press_time = KEY_SHORT_PRESS_TIME;
/* Store button configuration */
key_state_table[i].button_config = button_config;
}
/* Call board-specific button initialization if available */
if (board_config && board_config->init_funcs.button_init) {
board_config->init_funcs.button_init(&board_config->buttons);
}
}
/**
* @brief 更新按键状态(定期调用此函数,例如每 10ms
*/
void bsp_key_update(void) {
uint8_t i;
uint32_t current_time = bsp_key_get_time_ms();
for (i = 0; i < BSP_KEY_ID_MAX; i++) {
/* Skip if button configuration is not available */
if (!key_state_table[i].button_config) {
continue;
}
bsp_key_state_t raw_state = bsp_key_read_raw((bsp_key_id_t)i);
bsp_key_internal_state_t* key_state = &key_state_table[i];
/* Update current time */
key_state->current_time = current_time;
/* Debounce logic - optimized version */
if (raw_state != key_state->current_state) {
/* State is changing, increment counter */
if (++key_state->debounce_counter >= KEY_DEBOUNCE_COUNT) {
/* Debounce count reached, update state */
key_state->previous_state = key_state->current_state;
key_state->current_state = raw_state;
key_state->debounce_counter = 0;
if (raw_state == BSP_KEY_STATE_PRESSED) {
/* Key pressed event */
key_state->press_event = 1;
key_state->release_event = 0;
key_state->short_press_event = 0;
/* Reset timing variables */
key_state->press_start_time = current_time;
key_state->last_repeat_time = current_time;
key_state->long_press_event = 0;
key_state->repeat_event = 0;
} else {
/* Key released event */
key_state->release_event = 1;
key_state->press_event = 0;
/* Check for short press event */
uint32_t press_duration = current_time - key_state->press_start_time;
if (press_duration < key_state->long_press_time) {
key_state->short_press_event = 1;
}
/* Reset long press and repeat flags */
key_state->long_press_event = 0;
key_state->repeat_event = 0;
}
}
} else {
/* State is stable, reset counter */
key_state->debounce_counter = 0;
/* Handle timing-based events if key is pressed */
if (raw_state == BSP_KEY_STATE_PRESSED) {
uint32_t press_duration = current_time - key_state->press_start_time;
/* Check for long press event - only set once */
if (press_duration >= key_state->long_press_time && !key_state->long_press_event) {
key_state->long_press_event = 1;
}
/* Check for repeat event - only after long press */
if (key_state->long_press_event &&
(current_time - key_state->last_repeat_time >= key_state->repeat_interval)) {
key_state->repeat_event = 1;
key_state->last_repeat_time = current_time;
}
}
}
}
}
/**
* @brief 读取防抖后的按键状态
* @param key_id: 按键 ID
* @retval 按键状态
*/
bsp_key_state_t bsp_key_read(bsp_key_id_t key_id) {
if (key_id < BSP_KEY_ID_MAX) {
return key_state_table[key_id].current_state;
}
return BSP_KEY_STATE_RELEASED;
}
/**
* @brief 检查按键是否按下
* @param key_id: 按键 ID
* @retval 按下返回 1否则返回 0
*/
uint8_t bsp_key_is_pressed(bsp_key_id_t key_id) {
return (bsp_key_read(key_id) == BSP_KEY_STATE_PRESSED) ? 1 : 0;
}
/**
* @brief 检查按键是否释放
* @param key_id: 按键 ID
* @retval 释放返回 1否则返回 0
*/
uint8_t bsp_key_is_released(bsp_key_id_t key_id) {
return (bsp_key_read(key_id) == BSP_KEY_STATE_RELEASED) ? 1 : 0;
}
/**
* @brief 检查按键按下事件(边沿检测)
* @param key_id: 按键 ID
* @retval 按下事件返回 1否则返回 0
*/
uint8_t bsp_key_get_press_event(bsp_key_id_t key_id) {
uint8_t event = 0;
if (key_id < BSP_KEY_ID_MAX) {
event = key_state_table[key_id].press_event;
key_state_table[key_id].press_event = 0; /* Clear event flag */
}
return event;
}
/**
* @brief 检查按键释放事件(边沿检测)
* @param key_id: 按键 ID
* @retval 释放事件返回 1否则返回 0
*/
uint8_t bsp_key_get_release_event(bsp_key_id_t key_id) {
uint8_t event = 0;
if (key_id < BSP_KEY_ID_MAX) {
event = key_state_table[key_id].release_event;
key_state_table[key_id].release_event = 0; /* Clear event flag */
}
return event;
}
/**
* @brief 检查按键长按事件
* @param key_id: 按键 ID
* @retval 长按事件返回 1否则返回 0
*/
uint8_t bsp_key_get_long_press_event(bsp_key_id_t key_id) {
uint8_t event = 0;
if (key_id < BSP_KEY_ID_MAX) {
event = key_state_table[key_id].long_press_event;
/* Long press event is only reported once */
}
return event;
}
/**
* @brief 检查按键重复事件
* @param key_id: 按键 ID
* @retval 重复事件返回 1否则返回 0
*/
uint8_t bsp_key_get_repeat_event(bsp_key_id_t key_id) {
uint8_t event = 0;
if (key_id < BSP_KEY_ID_MAX) {
event = key_state_table[key_id].repeat_event;
key_state_table[key_id].repeat_event = 0; /* Clear event flag */
}
return event;
}
/**
* @brief 检查按键短按事件
* @param key_id: 按键 ID
* @retval 短按事件返回 1否则返回 0
*/
uint8_t bsp_key_get_short_press_event(bsp_key_id_t key_id) {
uint8_t event = 0;
if (key_id < BSP_KEY_ID_MAX) {
event = key_state_table[key_id].short_press_event;
key_state_table[key_id].short_press_event = 0; /* Clear event flag */
}
return event;
}