button部分直接上代码, 先满足调试功能, 可以看到里面还有一些尚未完成的部分.
整体的思路是外部中断函数中触发按键, 然后启动一个定时器进行按键扫描, 状态机输出按键事件, 再利用任务通知直接恢复按键任务的阻塞状态进行按键事件的分发处理. 如果没有按键按下整个按键任务是堵塞状态, 主要是为了方便主控休眠而没有采用osDelay的方法.
按键事件的handler包括了按键初始化, 按键事件注册, 按键事件状态机扫描, 分层设计.欢迎留言
/* Include file --------------------------------------------------------------*/
#include <stdio.h>
#include "cmsis_os.h"
#include "limits.h"
#include "tim.h"
#include "iwdg.h"
#include "rtc.h"
#include "low_power_mgr.h"
#include "database.h"
#include "dbg_printf.h"
#include "btn.h"
#include "exflash.h"
#include "fp.h"
#if (BUTTONS_NUMBER > 0)
/* Private typedef -----------------------------------------------------------*/
typedef struct BUTTON_MGR {
uint16_t gpio_pin;
GPIO_TypeDef *gpio_port;
uint32_t ticks;
bsp_button_action_t action;
bsp_button_event_t event;
} button_mgr_t;
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static __IO uint16_t m_button_auth_masks = 0; /**< */
static button_mgr_t m_events_list[BUTTONS_NUMBER] = {
#ifdef BUTTON_0
{EXTI00_HOME_SYS_WKUP_Pin, EXTI00_HOME_SYS_WKUP_GPIO_Port},
#endif
#ifdef BUTTON_1
{EXTI08_BUTTON0_Pin, GPIOD},
#endif
#ifdef BUTTON_2
{EXTI09_BUTTON1_Pin, GPIOD},
#endif
#ifdef BUTTON_3
{EXTI10_BUTTON2_Pin, GPIOD},
#endif
#ifdef BUTTON_4
{EXTI11_BUTTON3_Pin, GPIOD},
#endif
#ifdef BUTTON_5
{EXTI12_BUTTON4_Pin, GPIOD},
#endif
#ifdef BUTTON_6
{EXTI13_BUTTON5_Pin, GPIOD},
#endif
#ifdef BUTTON_7
{EXTI06_FP_SYS_WKUP_Pin, EXTI06_FP_SYS_WKUP_GPIO_Port},
#endif
};
extern osThreadId myTaskButtonHandle;
extern osThreadId myTaskRunStateHandle;
/* Private function prototypes -----------------------------------------------*/
static void bsp_button_init(void);
static bool bsp_button_startup_configure(void);
static bool bsp_event_button_action_assign(bsp_button_id_t button, bsp_button_action_t action, bsp_event_t event);
static uint8_t button_trigger_push(uint16_t gpio_pin);
static bsp_event_t button_state_machine(bool *bsp_button_is_press, uint16_t period_ticks);
static void app_button_event_process(bsp_event_t event);
static bool button_auth_cancel(uint16_t button_mask);
/* Private functions ---------------------------------------------------------*/
static void bsp_button_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIO_InitStruct.Pin = EXTI08_BUTTON0_Pin | EXTI09_BUTTON1_Pin | EXTI10_BUTTON2_Pin | \
EXTI11_BUTTON3_Pin | EXTI12_BUTTON4_Pin | EXTI13_BUTTON5_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = EXTI00_HOME_SYS_WKUP_Pin;
HAL_GPIO_Init(EXTI00_HOME_SYS_WKUP_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = EXTI06_FP_SYS_WKUP_Pin;
HAL_GPIO_Init(EXTI06_FP_SYS_WKUP_GPIO_Port, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0);
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
void timer16_init(void)
{
htim16.Instance = TIM16;
htim16.Init.Prescaler = 800 - 1;
htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
htim16.Init.Period = 1000 - 1;
htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim16.Init.RepetitionCounter = 0;
htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim16) != HAL_OK) {
Error_Handler();
}
}
void app_button_init(void)
{
bsp_button_init();
timer16_init();
for (uint16_t num = 0; num < BUTTONS_NUMBER; num++) {
bsp_event_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);
m_events_list[num].event.push = BSP_EVENT_NOTHING;
m_events_list[num].event.push_long = BSP_EVENT_NOTHING;
m_events_list[num].event.push_long_3s = BSP_EVENT_NOTHING;
m_events_list[num].event.release = BSP_EVENT_NOTHING;
}
bsp_button_startup_configure();
}
void button_wkup_enable(void)
{
HAL_PWR_DisableWakeUpPin(EXTI00_HOME_SYS_WKUP_Pin);
HAL_PWR_EnableWakeUpPin(EXTI00_HOME_SYS_WKUP_Pin);
// HAL_PWR_DisableWakeUpPin(EXTI08_BUTTON0_Pin | EXTI09_BUTTON1_Pin | EXTI10_BUTTON2_Pin | \
// EXTI11_BUTTON3_Pin | EXTI12_BUTTON4_Pin | EXTI13_BUTTON5_Pin);
// HAL_PWR_EnableWakeUpPin(EXTI08_BUTTON0_Pin | EXTI09_BUTTON1_Pin | EXTI10_BUTTON2_Pin | \
EXTI11_BUTTON3_Pin | EXTI12_BUTTON4_Pin | EXTI13_BUTTON5_Pin);
/* add your code... */
/* add your code... */
HAL_PWREx_EnableInternalWakeUpLine();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF1 | PWR_FLAG_WUF2 | PWR_FLAG_WUF3 | PWR_FLAG_WUF4 | PWR_FLAG_WUF5);
}
void button_wkup_disable(void)
{
HAL_PWREx_DisableInternalWakeUpLine();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF1 | PWR_FLAG_WUF2 | PWR_FLAG_WUF3 | PWR_FLAG_WUF4 | PWR_FLAG_WUF5);
}
void StartTaskButton(void const *argument)
{
#if 0
const TickType_t xFrequency = BUTTON_TICKS_DEBOUNCE;
for(;;) {
bsp_event_t button_event = button_state_machine(NULL, 0);
if (BSP_EVENT_NOTHING != button_event) {
app_button_event_process(button_event);
}
osDelay(xFrequency);
}
#else
for (;;) {
osEvent signal = osSignalWait(0xFF, osWaitForever); /**< */
if (signal.status == osEventSignal) {
bsp_event_t event = (bsp_event_t)signal.value.signals;
app_button_event_process(event);
}
}
#endif
}
static void app_button_event_process(bsp_event_t event)
{
switch (event) {
case BSP_EVENT_KEY_0:
dbg_printf("button_0.\r\n");
break;
case BSP_EVENT_KEY_1:
dbg_printf("button_1.\r\n");
osSignalSet(myTaskRunStateHandle, 1);
break;
case BSP_EVENT_KEY_2:
dbg_printf("button_2.\r\n");
break;
case BSP_EVENT_KEY_3:
dbg_printf("button_3.\r\n");
// exflash_chip_erase();
break;
case BSP_EVENT_KEY_4:
dbg_printf("button_4.\r\n");
db_message_send(DB_READ, NULL);
break;
case BSP_EVENT_KEY_5:
dbg_printf("button_5.\r\n");
db_message_send(DB_WRITE, NULL);
break;
case BSP_EVENT_KEY_6:
dbg_printf("button_6.\r\n");
// db_message_send(DB_UPDATE, NULL);
break;
case BSP_EVENT_MODE_SELECT:
fp_sensor_wkup();
dbg_printf("mode select.\r\n");
db_message_send(DB_FORMAT, NULL);
break;
case BSP_EVENT_SLEEP:
dbg_printf("go to sleep.\r\n");
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {}
break;
case BSP_EVENT_WAKEUP:
dbg_printf("fp sensor touched.\r\n");
fp_sensor_wkup();
break;
default:
dbg_printf("unknow button event.\r\n");
break;
}
}
static bool bsp_event_button_action_assign(bsp_button_id_t button, bsp_button_action_t action, bsp_event_t event)
{
bool retval = true;
if (button < BUTTONS_NUMBER) {
if (event == BSP_EVENT_DEFAULT) {
event = BSP_EVENT_NOTHING;
}
switch (action) {
case BSP_BUTTON_ACTION_PUSH:
m_events_list[button].event.push = event;
break;
case BSP_BUTTON_ACTION_RELEASE:
m_events_list[button].event.release = event;
break;
case BSP_BUTTON_ACTION_PUSH_LONG:
m_events_list[button].event.push_long = event;
break;
case BSP_BUTTON_ACTION_PUSH_LONG_3S:
m_events_list[button].event.push_long_3s = event;
break;
default:
retval = false;
break;
}
} else {
retval = false;
}
return retval;
}
static bool bsp_button_startup_configure(void)
{
bool retval = false;
retval = bsp_event_button_action_assign(BSP_BUTTON_HOME, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_MODE_SELECT);
retval = bsp_event_button_action_assign(BSP_BUTTON_HOME, BSP_BUTTON_ACTION_PUSH_LONG_3S, BSP_EVENT_SLEEP);
retval = bsp_event_button_action_assign(BSP_BUTTON_1, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_KEY_1);
retval = bsp_event_button_action_assign(BSP_BUTTON_2, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_KEY_2);
retval = bsp_event_button_action_assign(BSP_BUTTON_3, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_KEY_3);
retval = bsp_event_button_action_assign(BSP_BUTTON_4, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_KEY_4);
retval = bsp_event_button_action_assign(BSP_BUTTON_5, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_KEY_5);
retval = bsp_event_button_action_assign(BSP_BUTTON_6, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_KEY_6);
retval = bsp_event_button_action_assign(BSP_BUTTON_FP, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_WAKEUP);
return retval;
}
static bsp_event_t button_state_machine(bool *bsp_button_is_press, uint16_t period_ticks)
{
bool button_is_press = false;
bsp_event_t event = BSP_EVENT_NOTHING;
for(uint16_t button = 0; button < BUTTONS_NUMBER; button++) {
if (m_button_auth_masks & (1 << button)) {
uint8_t pin_state = HAL_GPIO_ReadPin(m_events_list[button].gpio_port, m_events_list[button].gpio_pin);
if (pin_state == GPIO_PIN_SET) {
button_is_press = true;
m_events_list[button].ticks += period_ticks;
if (m_events_list[button].action == BSP_BUTTON_ACTION_RELEASE) {
m_events_list[button].action = BSP_BUTTON_ACTION_PUSH;
}
} else {
m_events_list[button].action = BSP_BUTTON_ACTION_RELEASE;
}
switch (m_events_list[button].action) {
case BSP_BUTTON_ACTION_PUSH:
if (m_events_list[button].ticks == BUTTON_TICKS_DEBOUNCE) {
event = m_events_list[button].event.push;
} else if (m_events_list[button].ticks >= BUTTON_TICKS_PUSH_LONG) {
m_events_list[button].action = BSP_BUTTON_ACTION_PUSH_LONG;
if (m_events_list[button].event.push_long != BSP_EVENT_NOTHING) {
event = m_events_list[button].event.push_long;
}
}
break;
case BSP_BUTTON_ACTION_RELEASE:
m_events_list[button].ticks = 0;
button_auth_cancel(1 << button);
m_events_list[button].action = BSP_BUTTON_ACTION_RELEASE;
if (m_events_list[button].event.release != BSP_EVENT_NOTHING) {
event = m_events_list[button].event.release;
}
break;
case BSP_BUTTON_ACTION_PUSH_LONG:
if (m_events_list[button].ticks >= BUTTON_TICKS_PUSH_LONG_3S) {
m_events_list[button].action = BSP_BUTTON_ACTION_PUSH_LONG_3S;
if (m_events_list[button].event.push_long_3s != BSP_EVENT_NOTHING) {
event = m_events_list[button].event.push_long_3s;
}
}
break;
case BSP_BUTTON_ACTION_PUSH_LONG_3S:
break;
default:
break;
}
}
}
*bsp_button_is_press = button_is_press;
return event;
}
/* Public function definiton ------------------------------------------------ */
void button_event_timer_handler(void)
{
bool button_is_press = false;
uint32_t notify_value = 0;
bsp_event_t event = button_state_machine(&button_is_press, 10);
if (button_is_press) {
if (event != BSP_EVENT_NOTHING) {
notify_value = (uint32_t)event;
int32_t v = osSignalSet(myTaskButtonHandle, notify_value);
}
} else {
HAL_TIM_Base_Stop_IT(&htim16);
}
}
static uint8_t button_trigger_push(uint16_t gpio_pin)
{
uint8_t retval = 0xff;
switch (gpio_pin) {
case EXTI00_HOME_SYS_WKUP_Pin:
retval = BUTTON_0;
break;
case EXTI08_BUTTON0_Pin:
retval = BUTTON_1;
break;
case EXTI09_BUTTON1_Pin:
retval = BUTTON_2;
break;
case EXTI10_BUTTON2_Pin:
retval = BUTTON_3;
break;
case EXTI11_BUTTON3_Pin:
retval = BUTTON_4;
break;
case EXTI12_BUTTON4_Pin:
retval = BUTTON_5;
break;
case EXTI13_BUTTON5_Pin:
retval = BUTTON_6;
break;
case EXTI06_FP_SYS_WKUP_Pin:
retval = BUTTON_7;
break;
default:
break;
}
return retval;
}
static bool button_try_get_auth(uint16_t button_mask)
{
if (button_mask & BSP_BUTTON_MASKS_PWD) { /**< */
if ((m_button_auth_masks & BSP_BUTTON_MASKS_PWD) == 0) { /**< */
m_button_auth_masks |= button_mask;
} else { /**< */
return false;
}
} else if (button_mask & BSP_BUTTON_MASKS_FUNCTION) { /**< */
if (1) {
}
m_button_auth_masks |= button_mask; /**< */
}
return true;
}
static bool button_auth_cancel(uint16_t button_mask)
{
m_button_auth_masks &= ~button_mask;
return true;
}
bool button_exti_irq_handler(uint16_t gpio_pin, uint32_t *notify_value)
{
uint8_t button = button_trigger_push(gpio_pin);
if (button < BUTTONS_NUMBER) { /* 尝试授权 */
return button_try_get_auth(1 << button);
}
return false;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
BaseType_t xHigherPriorityTaskWoken;
uint32_t notify_value = 0;
uint32_t retval = 0;
retval = taskENTER_CRITICAL_FROM_ISR();
if (button_exti_irq_handler(GPIO_Pin, ¬ify_value)) {
HAL_TIM_Base_Start_IT(&htim16);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
taskEXIT_CRITICAL_FROM_ISR(retval);
}
#endif