【STM32进阶系列】推荐一种好用的按键处理程序

相信很多刚接触STM32的程序员来说,都会选择一种开发板来学习,而开发板给出的例程也主要是针对初学者,提供一种简单的按键处理方法,让大家更容易理解。但在相对复杂的工程中,这种简单的扫面实现的按键程序有时会显得力不从心。今天给大家分享一段项目中实际应用的按键处理程序。

前端时间在做一个项目时用到了相对复杂的按键处理,于是找到了基于状态机实现按键处理的multi_button开源软件,结合自己的应用对其进行了改编,实现了按键长按、短按、开关状态检测等,使用起来非常方便。

该按键程序的核心是状态机处理函数,对程序中的各个按键(在button init 中声明)进行管理,定期检测按键状态,当发生松开、按下动作时,根据按键状态变化,生成不同的事件,可在回调函数中执行需要的应用。

  1. 状态图如下

  1. 按键状态机需要定时调用,一般调用时间间隔为5mS,代码如下:

void button_handler(struct button* handle)
{
    uint8_t read_gpio_level = handle->hal_button_Level();

    //ticks counter working..
    if((handle->state) > 0)
    {
        handle->ticks++;
    }

    /*------------button debounce handle---------------*/
    if(read_gpio_level != handle->button_level)
    {
        //not equal to prev one
        //continue read 3 times same new level change
        if(++(handle->debounce_cnt) >= DEBOUNCE_TICKS)
        {
            handle->button_level = read_gpio_level;
            handle->debounce_cnt = 0;
        }
    }
    else
    {
        // leved not change ,counter reset.
        handle->debounce_cnt = 0;
    }

    /*-----------------State machine-------------------*/
    switch (handle->state)
    {
    case 0:    //释放状态
        if(handle->button_level == handle->active_level)
        {
            handle->event = (uint8_t)PRESS_DOWN;
            EVENT_CB(PRESS_DOWN);
            handle->ticks  = 0;
            //handle->repeat = 1;
            handle->state  = 1;
        }
        else
        {
            handle->event = (uint8_t)NONE_PRESS;
        }
        break;

    case 1:    //短按状态
        if(handle->button_level != handle->active_level)
        {
            handle->event = (uint8_t)SHORT_PRESS_UP;
            EVENT_CB(SHORT_PRESS_UP);
            handle->ticks = 0;
            handle->state = 2;

        }
        else if(handle->ticks > LONG_TICKS)
        {
            handle->event = (uint8_t)LONG_PRESS_START;
            EVENT_CB(LONG_PRESS_START);
            handle->state = 2;
        }
        break;

    case 2:    //长按状态
        if(handle->button_level == handle->active_level)
        {
            handle->event = (uint8_t)LONG_PRESS_HOLD;
            if (handle->ticks % LONG_HOLD_CYC == 0)
            {
                EVENT_CB(LONG_PRESS_HOLD);
            }
        }
        else
        {
            handle->event = (uint8_t)LONG_PRESS_UP;
            EVENT_CB(LONG_PRESS_UP);

            handle->state = 0;
        }
        break;
    }
}
  1. 按键初始化函数,

void button_init(struct button* handle, uint8_t(*pin_level)(void), uint8_t active_level)
{
    memset(handle, 0, sizeof(struct button));
    handle->event = (uint8_t)NONE_PRESS;
    handle->hal_button_Level = pin_level;
    handle->button_level = handle->hal_button_Level();
    handle->active_level = active_level;
}
  1. 将按键事件添加到状态机事件列表中

void button_attach(struct button* handle, PressEvent event, BtnCallback cb)
{
    handle->cb[event] = cb;
}

5.启用按键,供状态机管理

int button_start(struct button* handle)
{
    struct button* target = head_handle;

    while(target)                 //遍历所有节点,避免重复插入
    {
        if(target == handle)
        {
            return -1;  //already exist.
        }

        target = target->next;    //遍历到最后一个节点后,跳出循环
    }

    handle->next = head_handle;    //新节点next指向上一个节点,第一个插入的节点next = NULL,时钟为尾
    head_handle = handle;        //自己变成头

    return 0;
}
  1. 按键状态机工作的滴答时钟函数

void button_ticks(void)
{
    struct button* target;

    for(target = head_handle; target != NULL; target = target->next)    //遍历所有节点
    {
        button_handler(target);
    }
}

总结,以上是一些主要函数的说明,详细的源码可从博主的博客中下载。感兴趣的可持续关注~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值