/* 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; }