UP 路径优化
This commit is contained in:
103
lib/key/inc/key.h
Normal file
103
lib/key/inc/key.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef HW_LIB_SIM_KEY_H
|
||||
#define HW_LIB_KEY_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define KEY_TICKS_INTERVAL 5 // 定时器间隔时间,单位为毫秒
|
||||
#define DEBOUNCE_TICKS 0 // 按键去抖动计数阈值,最大为7(0 ~ 7)
|
||||
#define SHORT_TICKS (300 / KEY_TICKS_INTERVAL) // 短按阈值,单位为定时器间隔的倍数
|
||||
#define LONG_TICKS (1000 / KEY_TICKS_INTERVAL) // 长按阈值,单位为定时器间隔的倍数
|
||||
#define KEY_STOP_FREE 1 // 按键停止释放状态标识
|
||||
|
||||
|
||||
typedef struct Key_List Key_t; // 定义结构体Key_t为Key_List的别名
|
||||
typedef void (*Key_Callback_t)(Key_t *key); // 定义函数指针类型Key_Callback_t,接受一个Key_t结构体指针参数
|
||||
|
||||
typedef enum {
|
||||
KEY_PRESS_DOWN = 0, // 按下事件
|
||||
KEY_PRESS_UP, // 弹起事件
|
||||
KEY_PRESS_REPEAT, // 重复按下事件
|
||||
KEY_SINGLE_CLICK, // 单击事件
|
||||
KEY_DOUBLE_CLICK, // 双击事件
|
||||
KEY_LONG_PRESS_START, // 长按开始事件
|
||||
KEY_LONG_PRESS_HOLD, // 长按保持事件
|
||||
number_of_event, // 事件总数
|
||||
KEY_ALL_EVENT, // 所有事件
|
||||
NONE_PRESS // 无按键事件
|
||||
} PressEvent; // 定义枚举类型PressEvent,表示按键事件类型
|
||||
|
||||
struct Key_List {
|
||||
Key_t *next; // 指向下一个按键结构体的指针
|
||||
uint16_t ticks; // 计时器
|
||||
uint8_t repeat: 4; // 按键重复次数,占4位
|
||||
uint8_t event: 4; // 当前按键事件类型,占4位
|
||||
uint8_t state: 3; // 按键状态,占3位
|
||||
uint8_t debounce_cnt: 3; // 按键去抖计数,占3位
|
||||
uint8_t active_level: 1; // 按键激活电平,占1位
|
||||
uint8_t key_level: 1; // 当前按键电平,占1位
|
||||
uint8_t key_id; // 按键ID
|
||||
uint8_t (*hal_read_pin)(uint8_t key_id_); // 函数指针,用于获取按键电平
|
||||
Key_Callback_t cb[number_of_event]; // 按键事件回调函数数组
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化按键结构体
|
||||
* @param key: [输入] 按键结构体指针
|
||||
* @param key_id: [输入] 按键ID
|
||||
* @param active_level: [输入] 激活电平
|
||||
* @param read_pin: [输入] 读取按键状态的函数指针
|
||||
* @return void
|
||||
* @example key_init(&my_key, 1, ACTIVE_HIGH, read_key_pin_func);
|
||||
**/
|
||||
void key_init(Key_t *key, uint8_t key_id, uint8_t active_level, uint8_t(*read_pin)(uint8_t));
|
||||
|
||||
/**
|
||||
* @brief 为按键设置回调函数
|
||||
* @param key: [输入] 按键结构体指针
|
||||
* @param event: [输入] 按键事件类型
|
||||
* @param cb: [输入] 回调函数指针
|
||||
* @param start: [输入] 是否立即启用
|
||||
* @return void
|
||||
* @example key_attach(&my_key, PRESS_EVENT_LONG_PRESS, key_callback_func, true);
|
||||
**/
|
||||
void key_attach(Key_t *key, PressEvent event, Key_Callback_t cb, bool start);
|
||||
|
||||
/**
|
||||
* @brief 获取按键当前事件
|
||||
* @param key: [输入] 指向按键结构体的指针
|
||||
* @return 当前按键事件
|
||||
* @example PressEvent current_event = get_key_event(&my_key);
|
||||
*/
|
||||
PressEvent get_key_event(Key_t *key);
|
||||
|
||||
/**
|
||||
* @brief 启动按键检测
|
||||
* @param key: [输入] 指向按键结构体的指针
|
||||
* @return 错误码,0表示成功
|
||||
* @example int result = key_start(&my_key);
|
||||
*/
|
||||
int key_start(Key_t *key);
|
||||
|
||||
/**
|
||||
* @brief 停止按键检测
|
||||
* @param key: [输入] 指向按键结构体的指针
|
||||
* @return void
|
||||
* @example key_stop(&my_key);
|
||||
*/
|
||||
void key_stop(Key_t *key);
|
||||
|
||||
/**
|
||||
* @brief 按键定时处理函数
|
||||
* @return void
|
||||
* @example key_ticks();
|
||||
*/
|
||||
void key_ticks(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif //HW_LIB_SIM_KEY_H
|
171
lib/key/key.cpp
Normal file
171
lib/key/key.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include <malloc.h>
|
||||
#include "key.h"
|
||||
|
||||
|
||||
#define EVENT_CB(ev) if(key->cb[ev])key->cb[ev](key)
|
||||
#define PRESS_REPEAT_MAX_NUM 15
|
||||
|
||||
|
||||
static Key_t *head_key = NULL;
|
||||
|
||||
static void key_state_switch(Key_t *key);
|
||||
|
||||
|
||||
void key_init(Key_t *key, uint8_t key_id, uint8_t active_level, uint8_t(*read_pin)(uint8_t)) {
|
||||
memset(key, 0, sizeof(Key_t));
|
||||
key->event = (uint8_t) NONE_PRESS;
|
||||
key->hal_read_pin = read_pin;
|
||||
key->key_level = !active_level;
|
||||
key->active_level = active_level;
|
||||
key->key_id = key_id;
|
||||
}
|
||||
|
||||
|
||||
void key_attach(Key_t *key, PressEvent event, Key_Callback_t cb, bool start) {
|
||||
// 如果事件类型为ALL_EVENT,则将回调函数cb分别赋值给所有事件类型
|
||||
if (event == KEY_ALL_EVENT) {
|
||||
for (uint8_t i = KEY_PRESS_UP; i < number_of_event; i++) {
|
||||
key->cb[i] = cb;
|
||||
}
|
||||
} else {
|
||||
// 否则,将回调函数cb赋值给指定的事件类型
|
||||
key->cb[event] = cb;
|
||||
}
|
||||
if (start)key_start(key);
|
||||
}
|
||||
|
||||
PressEvent get_key_event(Key_t *key) {
|
||||
return (PressEvent) (key->event);
|
||||
}
|
||||
|
||||
static void key_state_switch(Key_t *key) {
|
||||
// 读取按键的GPIO电平
|
||||
uint8_t read_gpio_level = key->hal_read_pin(key->key_id);
|
||||
|
||||
// 如果按键状态大于0,则增加ticks计数
|
||||
if ((key->state) > 0) key->ticks++;
|
||||
|
||||
// 按键去抖动处理
|
||||
if (read_gpio_level != key->key_level) {
|
||||
if (++(key->debounce_cnt) >= DEBOUNCE_TICKS) {
|
||||
key->key_level = read_gpio_level;
|
||||
key->debounce_cnt = 0;
|
||||
}
|
||||
} else {
|
||||
key->debounce_cnt = 0;
|
||||
}
|
||||
|
||||
// 状态机处理按键事件
|
||||
switch (key->state) {
|
||||
case 0:
|
||||
if (key->key_level == key->active_level) {
|
||||
key->event = (uint8_t) KEY_PRESS_DOWN;
|
||||
EVENT_CB(KEY_PRESS_DOWN);
|
||||
key->ticks = 0;
|
||||
key->repeat = 1;
|
||||
key->state = 1;
|
||||
} else {
|
||||
key->event = (uint8_t) NONE_PRESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (key->key_level != key->active_level) {
|
||||
key->event = (uint8_t) KEY_PRESS_UP;
|
||||
EVENT_CB(KEY_PRESS_UP);
|
||||
key->ticks = 0;
|
||||
key->state = 2;
|
||||
} else if (key->ticks > LONG_TICKS) {
|
||||
key->event = (uint8_t) KEY_LONG_PRESS_START;
|
||||
EVENT_CB(KEY_LONG_PRESS_START);
|
||||
key->state = 5;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (key->key_level == key->active_level) {
|
||||
key->event = (uint8_t) KEY_PRESS_DOWN;
|
||||
EVENT_CB(KEY_PRESS_DOWN);
|
||||
if (key->repeat != PRESS_REPEAT_MAX_NUM) {
|
||||
key->repeat++;
|
||||
}
|
||||
EVENT_CB(KEY_PRESS_REPEAT);
|
||||
key->ticks = 0;
|
||||
key->state = 3;
|
||||
} else if (key->ticks > SHORT_TICKS) {
|
||||
if (key->repeat == 1) {
|
||||
key->event = (uint8_t) KEY_SINGLE_CLICK;
|
||||
EVENT_CB(KEY_SINGLE_CLICK);
|
||||
} else if (key->repeat == 2) {
|
||||
key->event = (uint8_t) KEY_DOUBLE_CLICK;
|
||||
EVENT_CB(KEY_DOUBLE_CLICK);
|
||||
}
|
||||
key->state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (key->key_level != key->active_level) {
|
||||
key->event = (uint8_t) KEY_PRESS_UP;
|
||||
EVENT_CB(KEY_PRESS_UP);
|
||||
if (key->ticks < SHORT_TICKS) {
|
||||
key->ticks = 0;
|
||||
key->state = 2;
|
||||
} else {
|
||||
key->state = 0;
|
||||
}
|
||||
} else if (key->ticks > SHORT_TICKS) {
|
||||
key->state = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (key->key_level == key->active_level) {
|
||||
key->event = (uint8_t) KEY_LONG_PRESS_HOLD;
|
||||
EVENT_CB(KEY_LONG_PRESS_HOLD);
|
||||
} else {
|
||||
key->event = (uint8_t) KEY_PRESS_UP;
|
||||
EVENT_CB(KEY_PRESS_UP);
|
||||
key->state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
key->state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int key_start(Key_t *key) {
|
||||
Key_t *target = head_key;
|
||||
while (target) {
|
||||
if (target == key) return -1;
|
||||
target = target->next;
|
||||
}
|
||||
key->next = head_key;
|
||||
head_key = key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void key_stop(Key_t *key) {
|
||||
Key_t **curr;
|
||||
for (curr = &head_key; *curr;) {
|
||||
Key_t *entry = *curr;
|
||||
if (entry == key) {
|
||||
*curr = entry->next;
|
||||
#if KEY_STOP_FREE
|
||||
free(entry);
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
curr = &entry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void key_ticks(void) {
|
||||
Key_t *target;
|
||||
for (target = head_key; target; target = target->next) {
|
||||
key_state_switch(target);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user