MultiButton事件触发型按键驱动模块在高云FPGA上的移植

2023-09-24 12:10:14 浏览数 (2)

前两篇文章介绍了letter-shell串口终端和cmd-parse串口命令解析器在高云FPGA GW1NSR-4C SoC上的移植:

  • letter-shell串口终端在高云FPGA上的移植
  • cmd-parser串口命令解析器在高云FPGA上的移植

本文介绍一个非常简单、功能强大的按键驱动模块MultiButton在高云FPGA上的移植。

1. MultiButton简介

MultiButton, 一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。

MultiButton 项目遵循MIT开源许可协议,允许使用者自由的分发和修改,许可证条件比较宽松,目前已经收获了1042个Star。

MultiButton 采用标准C语言开发,基于面向对象的设计思想,每个按键对象使用一个独立的数据结构进行管理。

支持多种按键触发方式:

  • PRESS_DOWN,按键按下,每次按下都触发
  • PRESS_UP,按键弹起,每次松开都触发
  • PRESS_REPEAT,重复按下触发,变量repeat计数连击次数
  • SINGLE_CLICK,单击按键事件
  • DOUBLE_CLICK,双击按键事件
  • LONG_PRESS_START,达到长按时间阈值时触发一次
  • LONG_PRESS_HOLD,长按期间一直触发

2. MultiButton代码获取

项目的GitHub地址:

代码语言:javascript复制
https://github.com/0x1abin/MultiButton

如果国内访问不稳定,可以到GitCode镜像地址下载:

代码语言:javascript复制
https://gitcode.net/mirrors/0x1abin/MultiButton

源代码下载到本地:

代码语言:javascript复制
$ git clone https://gitcode.net/mirrors/0x1abin/MultiButton.git --depth=1
​
Cloning into 'MultiButton'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 9 (delta 2), reused 1 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), 5.67 KiB | 5.67 MiB/s, done.
Resolving deltas: 100% (2/2), done.

整个项目非常小巧,只有两个文件:multi_button.c和multi_button.h

3. MultiButton移植

MultiButton的移植非常简单,只需要把multi_button.c和multi_button.h两个文件添加到工程,再实现一个按键状态读取函数,再通过5ms定时器调用处理函数就完成了移植,支持多种嵌入式平台。

首先,包含头文件,并定义一个按键:

代码语言:javascript复制
#include "multi_button.h"
​
struct button btn1;

根据自己所使用的嵌入式平台,实现对按键状态的读取,我使用的是高云GW1NSR-4C FPGA SoC:

代码语言:javascript复制
uint8_t read_button_GPIO(void)
{
    return GPIO_ReadBits(GPIO0) & 1;
}

再实现一个通用的按键回调函数,用于处理不同触发条件下的响应,这里为了演示,是打印对应的字符串:

代码语言:javascript复制
void button_callback(void *button)
{
    PressEvent event = get_button_event((struct button *)button); 
    switch(event)
    {
        case PRESS_DOWN      : printf("PRESS_DOWN      rn"); break;
        case PRESS_UP        : printf("PRESS_UP        rn"); break;
        case PRESS_REPEAT    : printf("PRESS_REPEAT    rn"); break;
        case SINGLE_CLICK    : printf("SINGLE_CLICK    rn"); break;
        case DOUBLE_CLICK    : printf("DOUBLE_CLICK    rn"); break;
        case LONG_PRESS_START: printf("LONG_PRESS_STARTrn"); break;
        case LONG_PRESS_HOLD : printf("LONG_PRESS_HOLD rn"); break;
        default:
            break;
    }
}

初始化按键,并把按键触发事件和回调函数进行绑定:

代码语言:javascript复制
button_init(&btn1, read_button_GPIO, 0);
button_attach(&btn1, PRESS_DOWN,       button_callback);    //按键按下触发一次
button_attach(&btn1, PRESS_UP,         button_callback);    //按键松开触发一次
button_attach(&btn1, SINGLE_CLICK,     button_callback);    //按键单击触发一次
button_attach(&btn1, DOUBLE_CLICK,     button_callback);    //按键双击触发一次
button_attach(&btn1, LONG_PRESS_START, button_callback);    //按键长按触发一次
​
button_start(&btn1);

以上准备就绪后,还剩下最后一个步骤,以5ms的周期定时调用按键状态处理函数:

代码语言:javascript复制
while(1)
{
    if(cnt_1ms >= 5)
    {
        cnt_1ms = 0;
        button_ticks();
    }
}

1ms我是采用的定时器中断的方式进行计数。

代码语言:javascript复制
//Timer0 interrupt handler
void TIMER0_Handler(void)
{
    if(TIMER_GetIRQStatus(TIMER0) != RESET)
    {
        cnt_1ms  ;
        TIMER_ClearIRQ(TIMER0);
    }
}

这样就完成了MultiButton在高云GW1NSR-4C FPGA上的移植。

4. 测试与运行

编译,下载bin文件,打开串口助手,并开启时间戳显示,分别测试按键按下、抬起、单击、双击、长按等触发方式。

测试日志如下:

代码语言:javascript复制
//单击测试1
PRESS_DOWN      [2023-09-23 09:25:10.789]
PRESS_UP        [2023-09-23 09:25:10.974]
SINGLE_CLICK    [2023-09-23 09:25:11.274]
//单击测试2
PRESS_DOWN      [2023-09-23 09:25:13.596]
PRESS_UP        [2023-09-23 09:25:13.783]
SINGLE_CLICK    [2023-09-23 09:25:14.093]
//双击测试1,300ms内两次按下    
PRESS_DOWN      [2023-09-23 09:25:15.017]
PRESS_UP        [2023-09-23 09:25:15.148]
PRESS_DOWN      [2023-09-23 09:25:15.214]
PRESS_UP        [2023-09-23 09:25:15.332]
DOUBLE_CLICK    [2023-09-23 09:25:15.647]
//双击测试2,300ms内两次按下   
PRESS_DOWN      [2023-09-23 09:25:17.589]
PRESS_UP        [2023-09-23 09:25:17.689]
PRESS_DOWN      [2023-09-23 09:25:17.758]
PRESS_UP        [2023-09-23 09:25:17.906]
DOUBLE_CLICK    [2023-09-23 09:25:18.214]
//长按测试1,识别时间1000ms    
PRESS_DOWN      [2023-09-23 09:25:18.896]
LONG_PRESS_START[2023-09-23 09:25:19.910]
PRESS_UP        [2023-09-23 09:25:20.711]
//长按测试2,识别时间1000ms   
PRESS_DOWN      [2023-09-23 09:25:21.698]
LONG_PRESS_START[2023-09-23 09:25:22.702]
PRESS_UP        [2023-09-23 09:25:23.003]

按键触发的灵敏度,单击、双击、长按的识别时间阈值,可以在头文件中进行修改:

代码语言:javascript复制
//According to your need to modify the constants.
#define TICKS_INTERVAL    5 //ms
#define DEBOUNCE_TICKS    3 //MAX 7 (0 ~ 7)
#define SHORT_TICKS       (300  / TICKS_INTERVAL)
#define LONG_TICKS        (1000 / TICKS_INTERVAL)
#define LONG_HOLD_CYC     (500 / TICKS_INTERVAL)

以上是默认条件,按下并保持1000ms认为是长按。

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

0 人点赞