目录
版本:https://github.com/murphyzhao/FlexibleButton/releases/tag/2.0.1
问题现象
问题描述
查源码!
注册
读按键
按键处理
小结
版本:https://github.com/murphyzhao/FlexibleButton/releases/tag/2.0.1https://github.com/murphyzhao/FlexibleButton/releases/tag/2.0.1
问题现象
static uint8_t common_btn_read(void *arg)
static void common_btn_evt_cb(void *arg)
这两个用户代码中的ID是相反的
问题描述
typedef enum
{
USER_BUTTON_1 = 0,
USER_BUTTON_2,
USER_BUTTON_3,
// USER_BUTTON_4,
USER_BUTTON_MAX
} user_button_t;
case USER_BUTTON_1:
value = PEin(6);
break;
case USER_BUTTON_2:
value = PCin(7);
break;
case USER_BUTTON_3:
value = PEin(5);
break;
static void common_btn_evt_cb(void *arg)
{
flex_button_t *btn = (flex_button_t *)arg;
DEBUG("id: [%d - %s] event: [%d - %30s] repeat: %d\r\n",
btn->id, enum_btn_id_string[btn->id],
btn->event, enum_event_string[btn->event],
btn->click_cnt);
}
正常逻辑 再回调 id = 0的时候应该对应的是 USER_BUTTON_1 (PE6)
实际测试的情况是 id = 0的时候应该对应的是 USER_BUTTON_3 (PE5)
顺序正好是逆序。其他功能都是正常的,虽然能用但是非常不爽。
查源码!
注册
static void user_button_init(void)
{
int i;
memset(&user_button[0], 0x0, sizeof(user_button));
for (i = 0; i < USER_BUTTON_MAX; i ++)
{
user_button[i].id = i;
user_button[i].usr_button_read = common_btn_read;
user_button[i].cb = common_btn_evt_cb;
user_button[i].pressed_logic_level = 0;
user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500);
user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000);
user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500);
flex_button_register(&user_button[i]);
}
}
/**
* First registered button is at the end of the 'linked list'.
* btn_head points to the head of the 'linked list'.
*/
button->next = btn_head;
button->status = FLEX_BTN_STAGE_DEFAULT;
button->event = FLEX_BTN_PRESS_NONE;
button->scan_cnt = 0;
button->click_cnt = 0;
button->max_multiple_clicks_interval = MAX_MULTIPLE_CLICKS_INTERVAL;
btn_head = button;
可以看到原作者这里使用了链表,如下图
读按键
/**
* @brief Read all key values in one scan cycle
*
* @param void
* @return none
*/
static void flex_button_read(void)
{
uint8_t i;
flex_button_t* target;
/* The button that was registered first, the button value is in the low position of raw_data */
btn_type_t raw_data = 0;
for(target = btn_head, i = button_cnt - 1;
(target != NULL) && (target->usr_button_read != NULL);
target = target->next, i--)
{
raw_data = raw_data | ((target->usr_button_read)(target) << i);
}
g_btn_status_reg = (~raw_data) ^ g_logic_level;
}
重点看这里面的i;
原作者使用了一个32位的变量存放按键值,每个bit对应一个按键值;
typedef uint32_t btn_type_t;
读代码里面是这样对应的。
按键处理
/**
* @brief Handle all key events in one scan cycle.
* Must be used after 'flex_button_read' API
*
* @param void
* @return none
*/
static void flex_button_process(void)
{
uint8_t i;
flex_button_t* target;
// for (target = btn_head, i = 0; target != NULL; target = target->next, i ++)
for (target = btn_head, i = button_cnt - 1; target != NULL; target = target->next, i--)
{
if (target->status > FLEX_BTN_STAGE_DEFAULT)
{
target->scan_cnt ++;
if (target->scan_cnt >= ((1 << (sizeof(target->scan_cnt) * 8)) - 1))
{
target->scan_cnt = target->long_hold_start_tick;
}
}
switch (target->status)
{
case FLEX_BTN_STAGE_DEFAULT: /* stage: default(button up) */
if (BTN_IS_PRESSED(i)) /* is pressed */
{
target->scan_cnt = 0;
target->click_cnt = 0;
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_DOWN);
/* swtich to button down stage */
target->status = FLEX_BTN_STAGE_DOWN;
}
else
{
target->event = FLEX_BTN_PRESS_NONE;
}
break;
case FLEX_BTN_STAGE_DOWN: /* stage: button down */
if (BTN_IS_PRESSED(i)) /* is pressed */
{
if (target->click_cnt > 0) /* multiple click */
{
if (target->scan_cnt > target->max_multiple_clicks_interval)
{
EVENT_SET_AND_EXEC_CB(target,
target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ?
target->click_cnt :
FLEX_BTN_PRESS_REPEAT_CLICK);
/* swtich to button down stage */
target->status = FLEX_BTN_STAGE_DOWN;
target->scan_cnt = 0;
target->click_cnt = 0;
}
}
else if (target->scan_cnt >= target->long_hold_start_tick)
{
if (target->event != FLEX_BTN_PRESS_LONG_HOLD)
{
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD);
}
}
else if (target->scan_cnt >= target->long_press_start_tick)
{
if (target->event != FLEX_BTN_PRESS_LONG_START)
{
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_START);
}
}
else if (target->scan_cnt >= target->short_press_start_tick)
{
if (target->event != FLEX_BTN_PRESS_SHORT_START)
{
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_START);
}
}
}
else /* button up */
{
if (target->scan_cnt >= target->long_hold_start_tick)
{
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD_UP);
target->status = FLEX_BTN_STAGE_DEFAULT;
}
else if (target->scan_cnt >= target->long_press_start_tick)
{
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_UP);
target->status = FLEX_BTN_STAGE_DEFAULT;
}
else if (target->scan_cnt >= target->short_press_start_tick)
{
EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_UP);
target->status = FLEX_BTN_STAGE_DEFAULT;
}
else
{
/* swtich to multiple click stage */
target->status = FLEX_BTN_STAGE_MULTIPLE_CLICK;
target->click_cnt ++;
}
}
break;
case FLEX_BTN_STAGE_MULTIPLE_CLICK: /* stage: multiple click */
if (BTN_IS_PRESSED(i)) /* is pressed */
{
/* swtich to button down stage */
target->status = FLEX_BTN_STAGE_DOWN;
target->scan_cnt = 0;
}
else
{
if (target->scan_cnt > target->max_multiple_clicks_interval)
{
EVENT_SET_AND_EXEC_CB(target,
target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ?
target->click_cnt :
FLEX_BTN_PRESS_REPEAT_CLICK);
/* swtich to default stage */
target->status = FLEX_BTN_STAGE_DEFAULT;
}
}
break;
}
}
}
注释掉的部分是源代码,下面是我修改之后的代码。
这里也是重点看“i”。
在遍历链表的时候,
BTN_IS_PRESSED(i)
原作者代码的i对应关系是,USER_BUTTON_3的链表使用了USER_BUTTON_1 引脚读取到的值。
那我们只要按照我上面给出的代码修改之后对应关系就正常了。
小结
原作者写的这份代码非常优秀,无论是实现的功能/可以执行都比我高出很多。具体就是在数据结构设计的时候我目前为止没有设计过带链表的数据结构,作者再这里面通过链表实现这些功能真的巧妙。