[单片机芯片]基于CH32V103移植事件驱动型按键驱动Multibutton过程分享

一. MultiButton
这次给大家带来的仍旧是作者0x1abin开源项目是 MultiButton,这是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。目前在GitHub收获 802 个star,遵循 MIT 开源许可。
MultiButton非常精简,麻雀虽小,五脏俱全!以下是GitHub开源链接:https://github.com/0x1abin/MultiButton

二. MultiButton的使用方法:
 

1.先申请一个按键结构
struct Button button1;
2.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平
button_init(&button1, read_button_pin, 0, 0);
3.注册按键事件
button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);

button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);

...
4.启动按键
button_start(&button1);
5.设置一个5ms间隔的定时器循环调用后台处理函数
while(1) {

    ...

    if(timer_ticks == 5) {

        timer_ticks = 0;



        button_ticks();

    }

}


二. MultiButton的特性与事件我们看完使用方法,可以发现它是每个按键对象单独用一份数据结构管理

struct Button {

        uint16_t ticks;

        uint8_t  repeat: 4;

        uint8_t  event : 4;

        uint8_t  state : 3;

        uint8_t  debounce_cnt : 3;

        uint8_t  active_level : 1;

        uint8_t  button_level : 1;

        uint8_t  button_id;

        uint8_t  (*hal_button_Level)(uint8_t  button_id_);

        BtnCallback  cb[number_of_event];

        struct Button* next;

};

好处是这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。
题我们一直强调MultiButton是一个事件驱动型按键驱动,那么它都支持哪些事件呢?
如下图,这是Multibutton支持的按键事件:

 




三. 移植MultiButton到CH32V103
1.新建工程与文件拷贝
mounriver新建工程真的很方便,大家可以参考:http://www.mounriver.com/help
文件拷贝的话,只要把multi_button.c和multi_button.h拷贝到工程目录即可,key.c和key.h是初始化ch32v103的gpio的。



2.实验平台
实验平台是我们自己设计的一款usb hid评估板,如下图:



板载8颗轻触开关,另外有一颗在摇杆电位器上,共9个按键。
原理图如下:

3.软件设计:
首先是9颗按键的初始化,主要在Key.c和key.h
因为SW1是摇杆电位器自带的,这里对应PA0,按下是高电平,这里需要下拉,其他按键是低电平按键都上拉。

void KEY_INIT(void)

{

  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;

  GPIO_Init(GPIOA, &GPIO_InitStructure);



  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6

                                  |GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

  GPIO_Init(GPIOB, &GPIO_InitStructure);



}

这些是SW1~SW9对应的端口定义,

#define     B1_GPIO_PORT        GPIOA

#define     B1_PIN              GPIO_Pin_0

#define     B2_GPIO_PORT        GPIOB

#define     B2_PIN              GPIO_Pin_9

#define     B3_GPIO_PORT        GPIOB

#define     B3_PIN              GPIO_Pin_8

#define     B4_GPIO_PORT        GPIOB

#define     B4_PIN              GPIO_Pin_7

#define     B5_GPIO_PORT        GPIOB

#define     B5_PIN              GPIO_Pin_6

#define     B6_GPIO_PORT        GPIOA

#define     B6_PIN              GPIO_Pin_15

#define     B7_GPIO_PORT        GPIOB

#define     B7_PIN              GPIO_Pin_3

#define     B8_GPIO_PORT        GPIOB

#define     B8_PIN              GPIO_Pin_4

#define     B9_GPIO_PORT        GPIOB

#define     B9_PIN              GPIO_Pin_5

按键已经初始化完成,接着是multibutton的使用了
第一步先定义按键号与句柄

enum Button_IDs {

    btn1_id,

    btn2_id,

    btn3_id,

    btn4_id,

    btn5_id,

    btn6_id,

    btn7_id,

    btn8_id,

    btn9_id,

};



struct Button btn1;

struct Button btn2;

struct Button btn3;

struct Button btn4;

struct Button btn5;

struct Button btn6;

struct Button btn7;

struct Button btn8;

struct Button btn9;

第二步是.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平

uint8_t read_button_GPIO(uint8_t button_id)

{

    // you can share the GPIO read function with multiple Buttons

    switch(button_id)

    {

        case btn1_id:

            return GPIO_ReadInputDataBit(B1_GPIO_PORT, B1_PIN);

        case btn2_id:

            return GPIO_ReadInputDataBit(B2_GPIO_PORT, B2_PIN);

        case btn3_id:

            return GPIO_ReadInputDataBit(B3_GPIO_PORT, B3_PIN);

        case btn4_id:

            return GPIO_ReadInputDataBit(B4_GPIO_PORT, B4_PIN);

        case btn5_id:

            return GPIO_ReadInputDataBit(B5_GPIO_PORT, B5_PIN);

        case btn6_id:

            return GPIO_ReadInputDataBit(B6_GPIO_PORT, B6_PIN);

        case btn7_id:

            return GPIO_ReadInputDataBit(B7_GPIO_PORT, B7_PIN);

        case btn8_id:

            return GPIO_ReadInputDataBit(B8_GPIO_PORT, B8_PIN);

        case btn9_id:

            return GPIO_ReadInputDataBit(B9_GPIO_PORT, B9_PIN);

        default:

            return 0;

    }

}

    button_init(&btn1, read_button_GPIO, 1, btn1_id);

    button_init(&btn2, read_button_GPIO, 0, btn2_id);

    button_init(&btn3, read_button_GPIO, 0, btn3_id);

    button_init(&btn4, read_button_GPIO, 0, btn4_id);

    button_init(&btn5, read_button_GPIO, 0, btn5_id);

    button_init(&btn6, read_button_GPIO, 0, btn6_id);

    button_init(&btn7, read_button_GPIO, 0, btn7_id);

    button_init(&btn8, read_button_GPIO, 0, btn8_id);

    button_init(&btn9, read_button_GPIO, 0, btn9_id);

第三步注册按键事件并启动,

    button_attach(&btn1, PRESS_DOWN,       BTN1_PRESS_DOWN_Handler);

    button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);

    button_attach(&btn2, PRESS_DOWN,       BTN2_PRESS_DOWN_Handler);

    button_attach(&btn2, PRESS_UP,         BTN2_PRESS_UP_Handler);

    button_attach(&btn3, PRESS_DOWN,       BTN3_PRESS_DOWN_Handler);

    button_attach(&btn3, PRESS_UP,         BTN3_PRESS_UP_Handler);

    button_attach(&btn4, PRESS_DOWN,       BTN4_PRESS_DOWN_Handler);

    button_attach(&btn4, PRESS_UP,         BTN4_PRESS_UP_Handler);

    button_attach(&btn5, PRESS_DOWN,       BTN5_PRESS_DOWN_Handler);

    button_attach(&btn5, PRESS_UP,         BTN5_PRESS_UP_Handler);

    button_attach(&btn6, PRESS_DOWN,       BTN6_PRESS_DOWN_Handler);

    button_attach(&btn6, PRESS_UP,         BTN6_PRESS_UP_Handler);

    button_attach(&btn7, PRESS_DOWN,       BTN7_PRESS_DOWN_Handler);

    button_attach(&btn7, PRESS_UP,         BTN7_PRESS_UP_Handler);

    button_attach(&btn8, PRESS_DOWN,       BTN8_PRESS_DOWN_Handler);

    button_attach(&btn8, PRESS_UP,         BTN8_PRESS_UP_Handler);

    button_attach(&btn9, PRESS_DOWN,       BTN9_PRESS_DOWN_Handler);

    button_attach(&btn9, PRESS_UP,         BTN9_PRESS_UP_Handler);

    button_start(&btn1);

    button_start(&btn2);

    button_start(&btn3);

    button_start(&btn4);

    button_start(&btn5);

    button_start(&btn6);

    button_start(&btn7);

    button_start(&btn8);

    button_start(&btn9);


最后设置一个5ms间隔的定时器循环调用后台处理函数,这里贴出main.c代码:

#include "debug.h"

#include "multi_button.h"

#include "key.h"



/* Global typedef */

enum Button_IDs {

    btn1_id,

    btn2_id,

    btn3_id,

    btn4_id,

    btn5_id,

    btn6_id,

    btn7_id,

    btn8_id,

    btn9_id,

};



struct Button btn1;

struct Button btn2;

struct Button btn3;

struct Button btn4;

struct Button btn5;

struct Button btn6;

struct Button btn7;

struct Button btn8;

struct Button btn9;

/* Global define */



/* Global Variable */







uint8_t read_button_GPIO(uint8_t button_id)

{

    // you can share the GPIO read function with multiple Buttons

    switch(button_id)

    {

        case btn1_id:

            return GPIO_ReadInputDataBit(B1_GPIO_PORT, B1_PIN);

        case btn2_id:

            return GPIO_ReadInputDataBit(B2_GPIO_PORT, B2_PIN);

        case btn3_id:

            return GPIO_ReadInputDataBit(B3_GPIO_PORT, B3_PIN);

        case btn4_id:

            return GPIO_ReadInputDataBit(B4_GPIO_PORT, B4_PIN);

        case btn5_id:

            return GPIO_ReadInputDataBit(B5_GPIO_PORT, B5_PIN);

        case btn6_id:

            return GPIO_ReadInputDataBit(B6_GPIO_PORT, B6_PIN);

        case btn7_id:

            return GPIO_ReadInputDataBit(B7_GPIO_PORT, B7_PIN);

        case btn8_id:

            return GPIO_ReadInputDataBit(B8_GPIO_PORT, B8_PIN);

        case btn9_id:

            return GPIO_ReadInputDataBit(B9_GPIO_PORT, B9_PIN);

        default:

            return 0;

    }

}







void BTN1_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN1_PRESS_DOWN\r\n");

}



void BTN1_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN1_PRESS_UP\r\n");

}



void BTN2_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN2_PRESS_DOWN\r\n");

}



void BTN2_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN2_PRESS_UP\r\n");

}

void BTN3_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN3_PRESS_DOWN\r\n");

}



void BTN3_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN3_PRESS_UP\r\n");

}

void BTN4_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN4_PRESS_DOWN\r\n");

}



void BTN4_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN4_PRESS_UP\r\n");

}

void BTN5_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN5_PRESS_DOWN\r\n");

}



void BTN5_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN5_PRESS_UP\r\n");

}



void BTN6_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN6_PRESS_DOWN\r\n");

}



void BTN6_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN6_PRESS_UP\r\n");

}

void BTN7_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN7_PRESS_DOWN\r\n");

}



void BTN7_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN7_PRESS_UP\r\n");

}

void BTN8_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN8_PRESS_DOWN\r\n");

}



void BTN8_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN8_PRESS_UP\r\n");

}



void BTN9_PRESS_DOWN_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN9_PRESS_DOWN\r\n");

}



void BTN9_PRESS_UP_Handler(void* btn)

{

    //do something...

    printf("\r\nBTN9_PRESS_UP\r\n");

}

/*********************************************************************

 * @fn      main

 *

 * [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.

 *

 * [url=home.php?mod=space&uid=266161]@return[/url]  none

 */

int main(void)

{

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    Delay_Init();

    USART_Printf_Init(115200);

    printf("SystemClk:%d\r\n", SystemCoreClock);



    printf("This is printf example\r\n");



    KEY_INIT();

    button_init(&btn1, read_button_GPIO, 1, btn1_id);

    button_init(&btn2, read_button_GPIO, 0, btn2_id);

    button_init(&btn3, read_button_GPIO, 0, btn3_id);

    button_init(&btn4, read_button_GPIO, 0, btn4_id);

    button_init(&btn5, read_button_GPIO, 0, btn5_id);

    button_init(&btn6, read_button_GPIO, 0, btn6_id);

    button_init(&btn7, read_button_GPIO, 0, btn7_id);

    button_init(&btn8, read_button_GPIO, 0, btn8_id);

    button_init(&btn9, read_button_GPIO, 0, btn9_id);



    button_attach(&btn1, PRESS_DOWN,       BTN1_PRESS_DOWN_Handler);

    button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);

    button_attach(&btn2, PRESS_DOWN,       BTN2_PRESS_DOWN_Handler);

    button_attach(&btn2, PRESS_UP,         BTN2_PRESS_UP_Handler);

    button_attach(&btn3, PRESS_DOWN,       BTN3_PRESS_DOWN_Handler);

    button_attach(&btn3, PRESS_UP,         BTN3_PRESS_UP_Handler);

    button_attach(&btn4, PRESS_DOWN,       BTN4_PRESS_DOWN_Handler);

    button_attach(&btn4, PRESS_UP,         BTN4_PRESS_UP_Handler);

    button_attach(&btn5, PRESS_DOWN,       BTN5_PRESS_DOWN_Handler);

    button_attach(&btn5, PRESS_UP,         BTN5_PRESS_UP_Handler);

    button_attach(&btn6, PRESS_DOWN,       BTN6_PRESS_DOWN_Handler);

    button_attach(&btn6, PRESS_UP,         BTN6_PRESS_UP_Handler);

    button_attach(&btn7, PRESS_DOWN,       BTN7_PRESS_DOWN_Handler);

    button_attach(&btn7, PRESS_UP,         BTN7_PRESS_UP_Handler);

    button_attach(&btn8, PRESS_DOWN,       BTN8_PRESS_DOWN_Handler);

    button_attach(&btn8, PRESS_UP,         BTN8_PRESS_UP_Handler);

    button_attach(&btn9, PRESS_DOWN,       BTN9_PRESS_DOWN_Handler);

    button_attach(&btn9, PRESS_UP,         BTN9_PRESS_UP_Handler);

    button_start(&btn1);

    button_start(&btn2);

    button_start(&btn3);

    button_start(&btn4);

    button_start(&btn5);

    button_start(&btn6);

    button_start(&btn7);

    button_start(&btn8);

    button_start(&btn9);

    while(1)

    {

        button_ticks();

        Delay_Ms(5);

    }

}



4.下载验证:
按下对应的按键,会有按下和松开事件的回调,特别适用于我们做usb hid的按键扫描!!

 

---------------------
作者:lilijin1995
链接:https://bbs.21ic.com/icview-3281398-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值