修复bug:FlexibleButton id相反问题

news/2025/4/2 5:11:33/

目录

版本: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 引脚读取到的值。

那我们只要按照我上面给出的代码修改之后对应关系就正常了。

小结

原作者写的这份代码非常优秀,无论是实现的功能/可以执行都比我高出很多。具体就是在数据结构设计的时候我目前为止没有设计过带链表的数据结构,作者再这里面通过链表实现这些功能真的巧妙。


http://www.ppmy.cn/news/69098.html

相关文章

shell脚本——流编辑器“三剑客”之sed命令

shell脚本——流编辑器“三剑客”之sed命令 一、流编辑器“三剑客”二、sed编辑器1、sed的工作流程2、命令格式3、常用选项4、常用操作5、打印内容6、使用地址7、删除行8、替换9、插入 一、流编辑器“三剑客” sed awk grep 二、sed编辑器 sed是一种流编辑器&#xff0c;流编…

Liunx top 命令详解

文章目录 top补充说明语法选项top交互命令实例 top 显示或管理执行中的程序 补充说明 top命令 可以实时动态地查看系统的整体运行情况&#xff0c;是一个综合了多方信息监测系统性能和运行信息的实用工具。通过top命令所提供的互动式界面&#xff0c;用热键可以管理。 语法…

HttpClient

介绍 介绍 HttpClient 是Apache Jakarta Common 下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议最新的版本和建议。 作用&#xff1a; 发送HTTP请求 接收响应数据 应用场景&#xff1a; …

Web的块级元素、行内元素和行内块元素区别、联系和相互转化

Web中&#xff0c;HTML元素可以分为三种类型&#xff1a;块级元素、行内元素和行内块元素。 名词解释 块级元素 是指在页面上以块的形式展现&#xff0c;单独占据一行或多行空间&#xff0c;如div、p、h1等。这些元素默认情况下会从上到下排列&#xff0c;同时宽度会自动填满…

Web开发中的标准流、浮动、定位的解释

在 Web 开发中&#xff0c;标准流、浮动和定位都是 Web 布局中常用的机制&#xff0c;各自都有其特点和适用范围。在实际开发中&#xff0c;需要根据需求选择合适的布局方式&#xff0c;并注意浏览器兼容性、性能优化等方面的问题。 标准流 标准流&#xff0c;也称文档流或普…

wecrush 笔试内容

CSS选择器的优先级计算方法&#xff0c;!important的作用 简述JS中的ES6 Module模块化规则 四种HTTP请求方法&#xff0c;两种HTTP传递参数的方法 两个栈实现一个队列&#xff0c;即appendTail和deleteHead操作 如果让你设计浏览器&#xff0c;你会如何划分进程。简述浏览器的进…

WiFi(Wireless Fidelity)基础(九)

目录 一、基本介绍&#xff08;Introduction&#xff09; 二、进化发展&#xff08;Evolution&#xff09; 三、PHY帧&#xff08;&#xff08;PHY Frame &#xff09; 四、MAC帧&#xff08;MAC Frame &#xff09; 五、协议&#xff08;Protocol&#xff09; 六、安全&#x…

双向带头循环链表的实现

1.学习第一步&#xff1a; 当我们要学习和了解一个事物时&#xff0c;我们要做的第一步便是对这个事物有一个体的的了解。现在我们要学习双向带头循环链表的第一步也是这个&#xff0c;我们现在先来了解一下这种链表的结构---- 就像该图所呈现的那样&#xff0c;双向循环链表就…