Files
chrg/apps/boot/bsp/bsp_key.c
T
2025-08-16 22:58:22 +08:00

275 lines
9.1 KiB
C

/* Includes ------------------------------------------------------------------*/
#include "bsp_key.h"
/* Private variables ---------------------------------------------------------*/
#define EVENT_CALLBACK(event) do{ \
if (key_index->Callback[ event ]) \
{ \
key_index->Callback[ event ]( key_index->id, event ); \
} \
} while(0)
/* Private function prototypes -----------------------------------------------*/
static struct BSP_KEY *_key_head;
/* Exported functions ---------------------------------------------------------*/
/**
* @brief 按键对象初始化
* @note
* @param[in] key: 按键句柄
* @param[in] id: 按键 ID,用于识别不同的按键
* @param[in] KEY_GetState: 按键状态获取回调函数
* @param[in] press_level: 按键按下时的电平状态
* @param[in] press_time: 设置按键长按的间隔时间
* @retval 执行结果
*/
#if (KEY_USER_DEFINE_PRESS_TIME)
int8_t BSP_Key_Init(struct BSP_KEY *key, uint8_t id, uint8_t (*KEY_GetState)(void), KEY_LEVEL press_level, uint16_t press_time)
#else
int8_t BSP_Key_Init(struct BSP_KEY *key, uint8_t id, uint8_t (*KEY_GetState)(void), KEY_LEVEL press_level)
#endif
{
memset(key, 0, sizeof(struct BSP_KEY));
key->id = id;
key->press_level = press_level;
key->continuous_value = 0xFF;
key->GetState = KEY_GetState;
#if (KEY_USER_DEFINE_PRESS_TIME)
key->press_time = press_time;
#endif
return 0;
}
/**
* @brief 按键启用
* @note 每个按键初始化并注册好相应的按键事件回调函数后,必须调用本函数才能使用
* @param[in] key: 按键句柄
* @retval 执行结果
*/
int8_t BSP_Key_Start(struct BSP_KEY *key)
{
struct BSP_KEY *key_index = _key_head;
while (key_index)
{
if (key_index == key)
return 1;
key_index = key_index->next;
}
key->next = _key_head;
_key_head = key;
return 0;
}
/**
* @brief 按键停用
* @note 当按键不再需要使用时,便可调用本函数
* @param[in] key:按键句柄
* @retval None
*/
void BSP_Key_Stop(struct BSP_KEY *key)
{
struct BSP_KEY *key_now = _key_head;
struct BSP_KEY *key_last;
for (; key_now; key_now = key_now->next)
{
if (key_now == key)
{
if (key == _key_head)
{
_key_head = key->next;
return;
}
if (key->next)
key_last->next = key->next;
else
key_last->next = NULL;
}
key_last = key_now;
}
}
/**
* @brief 注册按键事件触发时的回调函数
* @note 若需要使用按键,则至少应该注册一个按键事件的回调函数
* @param[in] key: 按键句柄
* @param[in] event: 按键事件
* @param[in] callback: 按键事件回调函数
* @retval None
*/
void BSP_Key_Register(struct BSP_KEY *key, KEY_EVENT event, Key_EventCallback callback)
{
key->Callback[ event ] = callback;
}
/**
* @brief 按键业务处理函数
* @note 若需要使用按键的任何功能,都需要调用本函数,并周期性的循环执行
* @param[in] ms: 告知本函数每隔多少毫秒被执行1次
* @retval None
*/
void BSP_Key_Handler(uint8_t ms)
{
uint8_t i = 0;
uint8_t times = 0xFF;
struct BSP_KEY *key_index = _key_head;
for (; i < (8 - KEY_CONSECUTIVE_READ_TIME); i++)
times >>= 1;
for (; key_index; key_index = key_index->next)
{
/* 获取按键电平值 */
key_index->continuous_value = (key_index->continuous_value << 1) | key_index->GetState();
/* 获取按键按下或弹起状态 */
if ((key_index->continuous_value & times) == 0x00)
{
if (key_index->press_level == KEY_PRESS_LOW)
key_index->key_state = KEY_DOWN;
else
key_index->key_state = KEY_UP;
}
else if((key_index->continuous_value & times) == times)
{
if (key_index->press_level == KEY_PRESS_HIGH)
key_index->key_state = KEY_DOWN;
else
key_index->key_state = KEY_UP;
}
/* 按键状态机 */
switch (key_index->state)
{
case 0:
{
if (key_index->key_state == KEY_DOWN) /* 首次按下 */
{
key_index->event = KEY_PRESS;
EVENT_CALLBACK( KEY_PRESS );
key_index->state = 1;
}
break;
}
case 1:
{
if (key_index->key_state == KEY_UP) /* 按下后放开 */
{
key_index->tick = 0;
#if (KEY_CLICK_EVENT_WHEN_DBLCLICK)
key_index->event = KEY_CLICK;
EVENT_CALLBACK( KEY_CLICK );
#endif
key_index->state = 2;
}
else if (key_index->key_state == KEY_DOWN) /* 还处于第一次按下的状态 */
{
key_index->tick += ms;
#if (KEY_USER_DEFINE_PRESS_TIME)
if (key_index->tick >= key_index->press_time) /* 第一次按下时间已超过长按触发时间 */
#else
if (key_index->tick >= KEY_LONG_PRESS_TIME) /* 超时未按下 */
#endif
{
key_index->tick = 0;
key_index->event = KEY_LONG_PRESS;
EVENT_CALLBACK( KEY_LONG_PRESS );
key_index->state = 4;
}
}
break;
}
case 2: /* 检测是否双击 */
{
if (key_index->key_state == KEY_DOWN) /* 单击后再次按下 */
{
if (KEY_DBLCLICK_PRESS_VALID) /* 第二次按下立即触发标志 */
{
key_index->event = KEY_DBLCLICK;
EVENT_CALLBACK( KEY_DBLCLICK );
}
key_index->tick = 0;
key_index->state = 3;
}
else if (key_index->key_state == KEY_UP) /* 未按下 */
{
key_index->tick += ms;
if (key_index->tick >= KEY_DBLCLICK_TIME) /* 单击后超时未再按下,事件结束 */
{
#if (KEY_CLICK_EVENT_WHEN_DBLCLICK == 0)
key_index->event = KEY_CLICK;
EVENT_CALLBACK( KEY_CLICK );
#endif
key_index->tick = 0;
key_index->state = 0;
key_index->event = KEY_NONE_EVENT;
}
}
break;
}
case 3: /* 双击事件,第二次已按下 */
{
if (key_index->key_state == KEY_UP) /* 第二次已放开按键 */
{
if (KEY_DBLCLICK_PRESS_VALID == 0) /* 第二次按下放开后才触发标志 */
{
key_index->event = KEY_DBLCLICK;
EVENT_CALLBACK( KEY_DBLCLICK );
}
key_index->tick = 0;
key_index->state = 0;
key_index->event = KEY_NONE_EVENT;
}
break;
}
case 4: /* 长时间按着(进入此处时长按回调事件已经被执行完毕) */
{
if (key_index->key_state == KEY_DOWN) /* 此时依旧被按着 */
{
key_index->tick += ms;
#if (KEY_LONG_PRESS_CONTINU_TRIG_TIME)
/* 需要长按保持触发 */
if (key_index->tick >= KEY_LONG_PRESS_CONTINU_TRIG_TIME)
{
key_index->tick = 0;
key_index->event = KEY_LONG_PRESS_HOLD;
EVENT_CALLBACK( KEY_LONG_PRESS_HOLD );
}
#endif
}
else if (key_index->key_state == KEY_UP) /* 用户已放开按键,流程结束 */
{
key_index->tick = 0;
key_index->state = 0;
key_index->event = KEY_NONE_EVENT;
}
break;
}
default :break;
}
}
}