STM32之按键驱动的使用和自定义(MultiButton)

这篇具有很好参考价值的文章主要介绍了STM32之按键驱动的使用和自定义(MultiButton)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原始Github地址

Github地址

修改后

调整内容

  1. 将宏定义转换成配置结构体

头文件

#ifndef _MULTI_BUTTON_H_
#define _MULTI_BUTTON_H_

#include "stdint.h"
#include "string.h"

//According to your need to modify the constants.
//#define TICKS_INTERVAL    5	//ms
//#define DEBOUNCE_TICKS    3	//MAX 8
//#define SHORT_TICKS       (300 /TICKS_INTERVAL)
//#define LONG_TICKS        (1000 /TICKS_INTERVAL)

#define BUTTON_DEFAULT_CONF {5,3,60,200}


typedef void (*BtnCallback)(void *);

typedef enum {
    PRESS_DOWN = 0,
    PRESS_UP,
    PRESS_REPEAT,
    SINGLE_CLICK,
    DOUBLE_CLICK,
    LONG_PRESS_START,
    LONG_PRESS_HOLD,
    number_of_event,
    NONE_PRESS
} PressEvent;

typedef 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 (*hal_button_Level)(void);

    BtnCallback cb[number_of_event];
    struct Button *next;
} Button;
struct Button_Conf {
    uint8_t interval_ticks; /*定时执行次数*/
    uint8_t debounce_ticks; /*消抖次数*/
    uint16_t short_press_timeout_ticks; /*短按超时次数*/
    uint16_t long_press_timeout_ticks; /*长按超时次数*/
};
#ifdef __cplusplus
extern "C" {
#endif

void button_init(struct Button *handle, uint8_t(*pin_level)(), uint8_t active_level);

void button_attach(struct Button *handle, PressEvent event, BtnCallback cb);

PressEvent get_button_event(struct Button *handle);

int button_start(struct Button *handle, struct Button_Conf *conf);

void button_stop(struct Button *handle);

void button_ticks(void);

#ifdef __cplusplus
}
#endif

#endif

源文件

/*
 * Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
 * All rights reserved
 */

#include "multi_button.h"

#define EVENT_CB(ev)   if(handle->cb[ev])handle->cb[ev]((Button*)handle)

//button handle list head.
static struct Button *head_handle = NULL;
static struct Button_Conf *button_conf = NULL;

/**
  * @brief  Initializes the button struct handle.
  * @param  handle:     按钮句柄.
  * @param  pin_level: 读取io状态回调.
  * @param  active_level: 按下时电平.
  * @retval None
  */
void button_init(struct Button *handle, uint8_t(*pin_level)(), 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;
}

/**
  * @brief  Attach the button event callback function.
  * @param  handle: the button handle strcut.
  * @param  event: trigger event type.
  * @param  cb: callback function.
  * @retval None
  */
void button_attach(struct Button *handle, PressEvent event, BtnCallback cb) {
    handle->cb[event] = cb;
}

/**
  * @brief  Inquire the button event happen.
  * @param  handle: the button handle strcut.
  * @retval button event.
  */
PressEvent get_button_event(struct Button *handle) {
    return (PressEvent) (handle->event);
}

/**
  * @brief  按钮驱动核心功能,驱动状态机。
  * @param  handle: the button handle strcut.
  * @retval None
  */
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) >= button_conf->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) {    //start press down
                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) { //released press up
                handle->event = (uint8_t) PRESS_UP;
                EVENT_CB(PRESS_UP);
                handle->ticks = 0;
                handle->state = 2;

            } else if (handle->ticks > button_conf->long_press_timeout_ticks) {
                handle->event = (uint8_t) LONG_PRESS_START;
                EVENT_CB(LONG_PRESS_START);
                handle->state = 5;
            }
            break;

        case 2:
            if (handle->button_level == handle->active_level) { //press down again
                handle->event = (uint8_t) PRESS_DOWN;
                EVENT_CB(PRESS_DOWN);
                handle->repeat++;
                EVENT_CB(PRESS_REPEAT); // repeat hit
                handle->ticks = 0;
                handle->state = 3;
            } else if (handle->ticks > button_conf->short_press_timeout_ticks) { //released timeout
                if (handle->repeat == 1) {
                    handle->event = (uint8_t) SINGLE_CLICK;
                    EVENT_CB(SINGLE_CLICK);
                } else if (handle->repeat == 2) {
                    handle->event = (uint8_t) DOUBLE_CLICK;
                    EVENT_CB(DOUBLE_CLICK); // repeat hit
                }
                handle->state = 0;
            }
            break;

        case 3:
            if (handle->button_level != handle->active_level) { //released press up
                handle->event = (uint8_t) PRESS_UP;
                EVENT_CB(PRESS_UP);
                if (handle->ticks < button_conf->short_press_timeout_ticks) {
                    handle->ticks = 0;
                    handle->state = 2; //repeat press
                } else {
                    handle->state = 0;
                }
            } else if (handle->ticks > button_conf->short_press_timeout_ticks) { // long press up
                handle->state = 0;
            }
            break;

        case 5:
            if (handle->button_level == handle->active_level) {
                //continue hold trigger
                handle->event = (uint8_t) LONG_PRESS_HOLD;
                EVENT_CB(LONG_PRESS_HOLD);

            } else { //releasd
                handle->event = (uint8_t) PRESS_UP;
                EVENT_CB(PRESS_UP);
                handle->state = 0; //reset
            }
            break;
    }
}

/**
  * @brief  Start the button work, add the handle into work list.
  * @param  handle: target handle strcut.
  * @param  conf: 对应配置
  * @retval 0: succeed. -1: already exist.
  */
int button_start(struct Button *handle, struct Button_Conf *conf) {
    struct Button *target = head_handle;
    button_conf = conf;
    while (target) {
        if (target == handle) return -1;    //already exist.
        target = target->next;
    }
    handle->next = head_handle;
    head_handle = handle;
    return 0;
}

/**
  * @brief  Stop the button work, remove the handle off work list.
  * @param  handle: target handle strcut.
  * @retval None
  */
void button_stop(struct Button *handle) {
    struct Button **curr;
    for (curr = &head_handle; *curr;) {
        struct Button *entry = *curr;
        if (entry == handle) {
            *curr = entry->next;
//			free(entry);
            return;//glacier add 2021-8-18
        } else
            curr = &entry->next;
    }
}

/**
  * @brief  background ticks, timer repeat invoking interval 5ms.
  * @param  None.
  * @retval None
  */
void button_ticks() {
    struct Button *target;
    if (button_conf == NULL)return;
    for (target = head_handle; target; target = target->next) {
        button_handler(target);
    }
}


测试

驱动使用

/*******************************************************************************
 Copyright (c) [scl]。保留所有权利。
    @brief 此为按键配置
 ******************************************************************************/
#include "app_conf.h"

#define DBG_ENABLE
#define DBG_SECTION_NAME "btn_cnf"
#define DBG_LEVEL DBG_LOG

#include "sys_dbg.h"
#include "dr_button.h"
#include "multi_button.h"

struct Button button; /*按钮结构体*/
struct Button_Conf btn_cnf = BUTTON_DEFAULT_CONF;
#define BUTTON_PIN stm_port_define(A,0)

static uint8_t read_button_pin() {
    return stm_pin_read(BUTTON_PIN);
}

static void btn_cb(void *arg) {
    struct Button *handle = (struct Button *) arg;

    PressEvent event = get_button_event(handle);

    switch (event) {
        case PRESS_DOWN:
            LOG_D("BUTTON EVENT:PRESS_DOWN");
            break;
        case PRESS_UP:
            LOG_D("BUTTON EVENT:PRESS_UP");
            break;
        case PRESS_REPEAT:
            LOG_D("BUTTON EVENT:PRESS_REPEAT");
            break;
        case SINGLE_CLICK:
            LOG_D("BUTTON EVENT:SINGLE_CLICK");
            break;
        case DOUBLE_CLICK:
            LOG_D("BUTTON EVENT:DOUBLE_CLICK");
            break;
        case LONG_PRESS_START:
            LOG_D("BUTTON EVENT:LONG_PRESS_START");
            break;
        case LONG_PRESS_HOLD:
            LOG_D("BUTTON EVENT:LONG_PRESS_HOLD");
            break;
        case number_of_event:
            LOG_D("BUTTON EVENT:number_of_event");
            break;
        case NONE_PRESS:
            LOG_D("BUTTON EVENT:NONE_PRESS");
            break;
    }

}

static void btn_cnf_pre_init() {
    btn_cnf.debounce_ticks = 4;
    // 初始化
    button_init(&button, read_button_pin, GPIO_PIN_SET);
    // 注册按键事件
//    button_attach(&button, SINGLE_CLICK, btn_cb);
//    button_attach(&button, DOUBLE_CLICK, btn_cb);
//    button_attach(&button, LONG_PRESS_START, btn_cb);
//    button_attach(&button, LONG_PRESS_HOLD, btn_cb);
//    button_attach(&button, PRESS_REPEAT, btn_cb);
    button_attach(&button, PRESS_DOWN, btn_cb);
    button_attach(&button, PRESS_UP, btn_cb);

    //启动按键
    button_start(&button, &btn_cnf);
}

sys_pre_init_export(btn_cnf, btn_cnf_pre_init);

static void btn_cnf_init() {
    stm32_pin_mode(BUTTON_PIN, pin_mode_input);
}

sys_init_export(btn_cnf, btn_cnf_init);

static void btn_cnf_after_init() {

}

sys_after_init_export(btn_cnf, btn_cnf_after_init);

执行循环逻辑 (在RTOS的定时器中执行)

/*******************************************************************************
 Copyright (c) [scl]。保留所有权利。
 ******************************************************************************/
#include "app_task.h"

#if OS_TIMER_LED
#define DBG_ENABLE /*日志是否启用*/
#define DBG_SECTION_NAME "led" /*日志模块名*/
#define DBG_LEVEL DBG_LOG /*日志等级*/

#include "sys_dbg.h"
#include "dr_led.h"
#include "multi_button.h"
/****************************************内部文件使用宏定义*************************************/
#define led_TIMER_TRIGGER 10 /*定时触发:ms(单位)*/
/****************************************外部变量引入****************************************************/
/****************************************变量定义****************************************************/
osTimerId led_timer;

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

static void led_run(void const *argument);

static void led_timer_create() {
    osTimerDef(led_timer, led_run);
    led_timer = osTimerCreate(osTimer(led_timer), osTimerPeriodic, NULL);

    osTimerStart(led_timer, led_TIMER_TRIGGER);
}

OS_TIMERS_EXPORT(led, led_timer_create);

/****************************************业务逻辑****************************************************/

static void led_run(void const *argument) {
//    LED_Toggle(LED_G);
    button_ticks(); // 执行按键循环检测
}

#endif

测试结果

STM32之按键驱动的使用和自定义(MultiButton),stm32,驱动开发,嵌入式硬件文章来源地址https://www.toymoban.com/news/detail-601575.html

到了这里,关于STM32之按键驱动的使用和自定义(MultiButton)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32MP157驱动开发——按键驱动(异步通知)

    Linux 系统中也有很多信号,在 Linux 内核源文件 includeuapiasm-genericsignal.h 中,有很多信号的宏定义: 就 APP 而言,你想处理 SIGIO 信息,那么需要提供信号处理函数,并且要跟 SIGIO 挂钩。这可以通过一个 signal 函数 来“给某个信号注册处理函数”,用法如下: 重点从②开始:

    2024年02月15日
    浏览(53)
  • 【嵌入式开源库】MultiButton的使用,简单易用的事件驱动型按键驱动模块

    MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。 本章使用环境: 正点原子stm32F4探索者 代码工程使用正点原子HAL库实验三-按键输

    2024年02月02日
    浏览(55)
  • 【嵌入式】使用MultiButton开源库驱动按键并控制多级界面切换

    目录 一 背景说明 二 参考资料 三 MultiButton开源库移植 四 设计实现--驱动按键 五 设计实现--界面处理         需要做一个 通过不同按键控制多级界面切换以及界面动作 的程序。         查阅相关资料,发现网上大多数的应用都比较繁琐,且对于多级界面的切换逻辑可读

    2024年02月07日
    浏览(61)
  • STM32MP157驱动开发——按键驱动(休眠与唤醒)

    当应用程序必须等待某个事件发生,比如必须等待按键被按下时,可以使用“休眠-唤醒”机制: ① APP 调用 read 等函数试图读取数据,比如读取按键; ② APP 进入内核态,也就是调用驱动中的对应函数,发现有数据则复制到用户空间并马上返回; ③ 如果 APP 在内核态,也就

    2024年02月16日
    浏览(42)
  • STM32MP157驱动开发——按键驱动(POLL 机制)

    使用休眠-唤醒的方式等待某个事件发生时,有一个缺点:等待的时间可能很久。我们可以加上一个超时时间,这时就可以使用 poll 机制。 ① APP 不知道驱动程序中是否有数据,可以先调用 poll 函数查询一下,poll 函数可以传入超时时间; ② APP 进入内核态, 调用到驱动程序的

    2024年02月15日
    浏览(38)
  • STM32MP157驱动开发——按键驱动(线程化处理)

    工作队列是在内核的线程的上下文中执行的 工作队列中有多个 work,前一个 work 没处理完会影响后面的 work。解决方法有如下2种: 比如自己创建一个内核线程,不跟别的 work 在一块。例如存储设备比如 SD/TF采用的就是单独一个线程。 使用线程化的中断处理。中断的处理仍然

    2024年02月16日
    浏览(43)
  • STM32MP157驱动开发——按键驱动(定时器)

    定时器涉及函数参考内核源码:includelinuxtimer.h 给定时器的各个参数赋值: 设置定时器 :主要是初始化 timer_list 结构体,设置其中的函数、参数。 a) 向内核添加定时器。timer-expires 表示超时时间。 b) 当超时时间到达,内核就会调用这个函数:timer-function(timer-data)。 修改定时

    2024年02月15日
    浏览(53)
  • 【STM32】步进电机及其驱动(ULN2003驱动28BYJ-48丨按键控制电机旋转)

    参考文章与课程:   【视频课程】步进电机基础原理和应用——程子华主讲   【视频课程】电机系列教学视频(基于STM32硬件)——野火   【霄耀在努力】STM32驱动步进电机(原理、程序、解决电机只震动不转动问题)   步进控制系统由以下三个部分组成: 控制器

    2023年04月09日
    浏览(49)
  • 蓝桥杯STM32 G431 hal库开发速成——按键+PWM综合案例——按键控制PWM驱动舵机

    适用于学习了TIM输出比较(PWM)跟GPIO输入(按键)的新手作为练习的综合项目! PWM(Pulse Width Modulation,脉冲宽度调制)是一种常用的技术,用于通过调节电信号的脉冲宽度(即脉冲的持续时间)来控制模拟系统的电源。在数字电子系统中,由于只能输出固定的高(通常为

    2024年01月21日
    浏览(60)
  • K_A08_009 基于 STM32等单片机驱动TB6612模块按键控制直流电机正反转加减速启停

    目录 一、资源说明 二、基本参数         1、参数         2、引脚说明 三、驱动说明         TB6612模块驱动说明         对应程序:         ENA ENB输出PWM 四、部分代码说明         接线说明                 1、STC89C52RC+TB6612模块                 2、STM32F

    2024年02月15日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包