902|3

37

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【极海APM32F4xx Tiny】学习笔记03-按键输入+自定义按键框架 [复制链接]

  本帖最后由 chejia12 于 2023-5-29 22:10 编辑

3.按键输入+自定义按键框架

按键框架使用条件:

1.已经初始化了gpio位输入状态或提供了初始化按键为输入的函数 2.注册按键事件 需要提供按键按下的有效电平 需要提供按键按下的事件处理函数 3.循环调用按键 key_lib_buttons_process 函数,一般1ms调用一次 BUTTON_DEBOUNCE_TIME_MS 一般设置为200 ,也就是200ms

 

按键实例教程:

  1. 提供了按键处理框架文件bsp_key_lib.c/h

  2. 提供了按键gpio设置为输入模式的函数bsp_key.c/h

  3. 提供了按键处理按键实例,及如何使用按键框架的bsp_button_instance.c/h

 

bsp_key_lib.c

​
#include "../key/bsp_key_lib.h"
#include "stdio.h"
#include "string.h"
​
​
​
​
static button *btuuon_head = NULL;
//核心检测代码
void button_cheeck(button *btn)
{
​
    volatile uint8_t current_level = 0;
​
    if(btn->fn_read_button_level)
        current_level = (uint8_t)btn->fn_read_button_level(btn->read_button_param); //获取当前按键电平
​
    if ((current_level != btn->last_level)                                                  //检测电平变化
            && (++(btn->debounce_time) >= BUTTON_DEBOUNCE_TIME_MS)) //按键电平发生变化,消抖
    {
        btn->last_level = current_level;                //更新当前按键电平
        btn->debounce_time = 0;                 //确定了是按下
​
        if (btn->triger_level == current_level)
        {
            btn->envent = BUTTON_DOWM; //按键状态
        }
        //释放按键
        else
        {
            btn->envent = BUTTON_UP;
        }
    }
​
    //处理按键事件
    if(btn->envent != BUTTON_NULL && btn->button_handles[(uint8_t)btn->envent])
    {
        btn->button_handles[(uint8_t)btn->envent](btn->id);
        btn->envent = BUTTON_NULL;
    }
​
}
​
​
void key_lib_register_button(button *btn, uint8_t id, uint8_t valid_level, read_button_level fn_read_button_level, button_event_type type, fn_button_handle handel,uint8_t param)
{
    btn->triger_level = valid_level;
    btn->fn_read_button_level = fn_read_button_level;
    btn->button_handles[(uint8_t)type] = handel;
    btn->id = id;
        btn->read_button_param =param;
    
    btn->envent = BUTTON_NULL;
    btn->debounce_time = 0;
        btn->last_level = fn_read_button_level(param);
        
​
    //形成一个链表结构
    if(!btuuon_head)
    {
        btuuon_head = btn;
    }
    else
    {
​
        button *pbtn = btuuon_head;
​
        //同一个按键注册多个时间处理
        for(; pbtn; pbtn = pbtn->next)
        {
            if(pbtn == btn)
            {
                return;
            }
        }
                
        //一个新的button注册事件
        pbtn = btuuon_head;
​
        for(; pbtn->next; pbtn = pbtn->next)
        {
​
        }
​
        pbtn->next = btn;
    }
}
​
void key_lib_register_button_ex(button *btn)
{
    
    btn->last_level=btn->fn_read_button_level(btn->read_button_param);
    btn->debounce_time=0;
    btn->envent = BUTTON_NULL;
        //形成一个链表结构
    if(!btuuon_head)
    {
        btuuon_head = btn;
    }
    else
    {
​
        button *pbtn = btuuon_head;
​
        //同一个按键注册多个时间处理
        for(; pbtn; pbtn = pbtn->next)
        {
            if(pbtn == btn)
            {
                return;
            }
        }
                
        //一个新的button注册事件
        pbtn = btuuon_head;
​
        for(; pbtn->next; pbtn = pbtn->next)
        {
​
        }
​
        pbtn->next = btn;
    }
}
​
/*定时器每1ms调用一次*/
void key_lib_buttons_process()
{
    button *pbtn = btuuon_head;
​
    for(; pbtn; pbtn = pbtn->next)
    {
        button_cheeck(pbtn);
    }
}
​
​

 

bsp_key_lib.h

#ifndef _BUTTON_H_
#define _BUTTON_H_ 
​
#include "stdint.h"
​
/*
    按键框架使用条件:
    1.已经初始化了gpio位输入状态或提供了初始化按键为输入的函数
    2.注册按键事件
        需要提供按键按下的有效电平
        需要提供按键按下的事件处理函数
    3.循环调用按键 key_lib_buttons_process 函数,一般1ms调用一次  BUTTON_DEBOUNCE_TIME_MS 一般设置为200 ,也就是200ms
*/
​
​
//按键消抖时间ms,一般是200ms,key_lib_buttons_process 函数的周期调用时间决定了这个地方的值
#define BUTTON_DEBOUNCE_TIME_MS 2  
​
​
#define INTERVAL 10
​
​
typedef enum 
{
    BUTTON_DOWM=0,//按键按下
    BUTTON_UP, //按键释放
        BUTTON_NULL//未知时间
}button_event_type;
​
​
/*************************旋钮宏定义**********************************/
​
/*
    按键状态
*/
typedef void (*fn_button_handle)(uint8_t btn_id);               //按键事件回调函数
typedef uint8_t  (*read_button_level)(uint8_t param);       //读取按键的回调函数
​
​
typedef struct button_
{
        uint8_t id;//id
        read_button_level fn_read_button_level;//电平去读函数
    uint8_t triger_level;                       //按键触发的有效电平
        uint8_t read_button_param;  
    fn_button_handle button_handles[BUTTON_NULL];//时间处理函数
    
      uint16_t debounce_time;                   //双击时间
        button_event_type envent;               //按键事件
        struct button_ *next;                       //下一个按键
        uint8_t last_level;                         //最后一次按键跳变的电平
} button;
​
/*
    每ms调用一次
*/
void key_lib_buttons_process(void);
/*
    注册按键检测事件
*/
void key_lib_register_button(button *btn,uint8_t id,uint8_t valid_level, read_button_level fn_read_button_level ,button_event_type type,fn_button_handle handel,uint8_t param);
​
void key_lib_register_button_ex(button *btn);
​
#endif
​
​

bsp_key.c

​
​
/* Includes */
 #include "../key/bsp_key.h"
​
//按键port
GPIO_T* BUTTON_PORT[BUTTONn] = {KEY1_BUTTON_GPIO_PORT, KEY2_BUTTON_GPIO_PORT};
//按键pin
const uint16_t BUTTON_PIN[BUTTONn] = {KEY1_BUTTON_PIN, KEY2_BUTTON_PIN};
//按键port
const uint32_t BUTTON_CLK[BUTTONn] = {KEY1_BUTTON_GPIO_CLK, KEY2_BUTTON_GPIO_CLK};
//外部中断先名
const EINT_LINE_T BUTTON_EINT_LINE[BUTTONn] = {KEY1_BUTTON_EINT_LINE, KEY2_BUTTON_EINT_LINE};
//外部中断源分组
const SYSCFG_PORT_T BUTTON_PORT_SOURCE[BUTTONn] = {KEY1_BUTTON_EINT_PORT_SOURCE, KEY2_BUTTON_EINT_PORT_SOURCE};
//外部中断源pin
const SYSCFG_PIN_T BUTTON_PIN_SOURCE[BUTTONn] = {KEY1_BUTTON_EINT_PIN_SOURCE, KEY2_BUTTON_EINT_PIN_SOURCE};
////外部中断源中断处理函数
const IRQn_Type BUTTON_IRQn[BUTTONn] = {KEY1_BUTTON_EINT_IRQn, KEY2_BUTTON_EINT_IRQn};
​
/*
    按键名称
    按键输入模式 0普通输入 ;1:中断输入
*/
void bsp_key_init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode)
{
    GPIO_Config_T     GPIO_configStruct;
    EINT_Config_T     EINT_configStruct;
​
    /** 使能按键时钟*/
    RCM_EnableAHB1PeriphClock(BUTTON_CLK[Button]);
​
    /** 配置gpio位输入模式,上拉 */
    GPIO_ConfigStructInit(&GPIO_configStruct);
    GPIO_configStruct.mode = GPIO_MODE_IN;//输入
    GPIO_configStruct.pin = BUTTON_PIN[Button];//PIN
    GPIO_configStruct.pupd  = GPIO_PUPD_UP;//上拉
    GPIO_Config(BUTTON_PORT[Button], &GPIO_configStruct);
​
    if (Button_Mode == BUTTON_MODE_EINT)//中断模式
    {
        /** Enable the SYSCFG Clock 使能系统时钟 */
        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
​
        /** Connect Button EINT Line to Button GPIO Pin 配置中断源 那个线*/
        SYSCFG_ConfigEINTLine(BUTTON_PORT_SOURCE[Button], BUTTON_PIN_SOURCE[Button]);
​
        /** Configure Button EINT line  中断使能*/
        EINT_configStruct.line = BUTTON_EINT_LINE[Button];
        EINT_configStruct.mode = EINT_MODE_INTERRUPT;
        EINT_configStruct.trigger = EINT_TRIGGER_FALLING;
        EINT_configStruct.lineCmd = ENABLE;
        EINT_Config(&EINT_configStruct);
​
        /** Enable and set Button EINT Interrupt to the lowest priority 配置中断优先级*/
        NVIC_EnableIRQRequest(BUTTON_IRQn[Button], 0x0f, 0x0f);
    }
}
​
/*
    读取按键状态
*/
uint8_t bsp_get_key(uint8_t Button)
{
    return GPIO_ReadInputBit(BUTTON_PORT[Button], BUTTON_PIN[Button]);
}
​
​
//uint8_t Key_Scan(uint8_t mode)
//{
//    /** The flag of button is release */
//    static uint8_t s_key_release = 1;
​
//    if(mode == KEY_MODE_CONTINUOUS)
//    {
//        s_key_release = 1;
//    }
​
//    if(s_key_release && (KEY1 == 0 || KEY2 == 0))
//    {
//        Delay_ms(10);
​
//        s_key_release = 0;
​
//        if(KEY1 == 0)
//        {
//            return KEY1_PRESSED;
//        }
//        else if(KEY2 == 0)
//        {
//            return KEY2_PRESSED;
//        }
//    }
//    else if(KEY1 == 1 && KEY2 == 1)
//    {
//        s_key_release = 1;
//    }
​
//    return KEY_ALL_REALEASED;
//}
​
​

 

bsp_key.h

/*!
 * @file        bsp_key.h
 *
 * @brief       Header for bsp_key.c module
 *
 * @version     V1.0.0
 *
 * @date        2023-03-01
 *
 * @attention
 *
 *  Copyright (C) 2021-2023 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */
​
/* Define to prevent recursive inclusion */
#ifndef __BSP_KEY_H
#define __BSP_KEY_H
​
#ifdef __cplusplus
  extern "C" {
#endif
​
/* Includes */
//#include "Board.h"
#include "bsp_delay.h"
#include "apm32f4xx.h"
#include "apm32f4xx_gpio.h"
#include "apm32f4xx_eint.h"
#include "apm32f4xx_rcm.h"
#include "apm32f4xx_syscfg.h"
#include "apm32f4xx_misc.h"
​
​
typedef enum
{
    BUTTON_KEY1 = 0,
    BUTTON_KEY2 = 1,
        BUTTONn
} Button_TypeDef;
​
typedef enum
{
    BUTTON_MODE_GPIO = 0,
    BUTTON_MODE_EINT = 1
} ButtonMode_TypeDef;
​
​
​
/**
 * @brief 按键1
 */
#define KEY1_BUTTON_PIN                   GPIO_PIN_10
#define KEY1_BUTTON_GPIO_PORT             GPIOC
#define KEY1_BUTTON_GPIO_CLK              RCM_AHB1_PERIPH_GPIOC
#define KEY1_BUTTON_EINT_LINE             EINT_LINE_10
#define KEY1_BUTTON_EINT_PORT_SOURCE      SYSCFG_PORT_GPIOC
#define KEY1_BUTTON_EINT_PIN_SOURCE       SYSCFG_PIN_10
#define KEY1_BUTTON_EINT_IRQn             EINT15_10_IRQn
/**
 * @brief 按键2
 */
#define KEY2_BUTTON_PIN                   GPIO_PIN_11
#define KEY2_BUTTON_GPIO_PORT             GPIOC
#define KEY2_BUTTON_GPIO_CLK              RCM_AHB1_PERIPH_GPIOC
#define KEY2_BUTTON_EINT_LINE             EINT_LINE_11
#define KEY2_BUTTON_EINT_PORT_SOURCE      SYSCFG_PORT_GPIOC
#define KEY2_BUTTON_EINT_PIN_SOURCE       SYSCFG_PIN_11
#define KEY2_BUTTON_EINT_IRQn             EINT15_10_IRQn
​
​
​
​
/*
    按键名称
    按键输入模式 0普通输入 ;1:中断输入
*/
void bsp_key_init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode);
​
/*
    读取按键状态
*/
uint8_t bsp_get_key(uint8_t Button);
​
//#define KEY1                GPIO_ReadInputBit(KEY1_BUTTON_GPIO_PORT,KEY1_BUTTON_PIN)
//#define KEY2                GPIO_ReadInputBit(KEY2_BUTTON_GPIO_PORT,KEY2_BUTTON_PIN)
​
///**
//  * @}
//  */
​
///** @defgroup APM32F407_TINY_Enumerations
//  @{
//  */
​
///*!
// * @brief    Key value
// */
//typedef enum
//{
//    KEY_ALL_REALEASED,      /*!< All key is realeased */
//    KEY1_PRESSED,           /*!< KEY1 is pressed */
//    KEY2_PRESSED,           /*!< KEY2 is pressed */
//} KEY_VALUE_T;
​
///*!
// * @brief    Key mode
// */
//typedef enum
//{
//    KEY_MODE_SINGLE,            /*!< Single detect mode */
//    KEY_MODE_CONTINUOUS,        /*!< Continuous detect mode */
//} KEY_MODE_T;
​
///**
//  * @}
//  */
​
///** @defgroup APM32F407_TINY_Functions
//  @{
//  */
​
///** function declaration*/
//uint8_t Key_Scan(uint8_t mode);
​
#ifdef __cplusplus
}
#endif
​
#endif
​
/**@} end of group APM32F407_TINY_Functions */
/**@} end of group Board_APM32F407_TINY */
/**@} end of group Board */
​

 

bsp_button_instance.c

​
#include "string.h"
#include <stdio.h>
#include "../key/bsp_button_instance.h"
#include "../key/bsp_key.h"
//-------------------实际使用-------------------------------
//static button btn0,btn1;
​
static void btn_gpio_init(void)
{
    bsp_key_init(BUTTON_KEY1,BUTTON_MODE_GPIO);
    bsp_key_init(BUTTON_KEY2,BUTTON_MODE_GPIO);
}
​
​
​
void button_down_handles(uint8_t btn_id);
​
void button_up_handles(uint8_t btn_id);
​
button btnx= {
    0,//id
    bsp_get_key,//get_level
    BUTTON_DOWM,
    BUTTON_KEY1,
    {button_down_handles,0},
};
​
button btny= {
    1,//id
    bsp_get_key,//按键读取函数
    BUTTON_DOWM,//有效电平
    BUTTON_KEY2,//按键读取函数参数
    {button_down_handles,0},//处理函数可以填写2个处理函数
};
​
​
void init_key_btn(void)
{
​
    btn_gpio_init();
    //按下按键注册
    //key_lib_register_button(&btn0, 0, RESET, bsp_get_key, BUTTON_DOWM, button_down_handles,BUTTON_KEY1);
    //key_lib_register_button(&btn1, 1, RESET, bsp_get_key, BUTTON_DOWM, button_down_handles,BUTTON_KEY2);
​
    key_lib_register_button_ex(&btnx);
    key_lib_register_button_ex(&btny);
​
}
​
​
​
void button_up_handles(uint8_t btn_id)
{
#if BUTTON_DEBUG >0
    printf("%s %s %d btn_id = %d \r\n", __FILE__, __FUNCTION__, __LINE__, btn_id);
#endif
​
​
}
​
void button_down_handles(uint8_t btn_id)
{
#if BUTTON_DEBUG >0
    printf("%s %s %d btn_id = %d \r\n", __FILE__, __FUNCTION__, __LINE__, btn_id);
#endif
​
}
​
//void button_handles(uint8_t btn_id)
//{
//    #if BUTTON_DEBUG >0
//    #endif
//    //处理摇杆数据
//
//}
​
​

 

bsp_button_instance.h

#ifndef _BUTTON_INSTANCEH_
#include "stdint.h"
#include "../key/bsp_key_lib.h"
​
​
#define DEBUG 1
​
#if DEBUG >0
#define BUTTON_DEBUG 1
#endif
void init_key_btn(void);
​
void button_handles(uint8_t btn_id);
​
#endif
​

 

main.c 调用

int main(void)
{
    led_init(LED0);
    led_init(LED1);
        bsp_uart1_init(115200);
        printf("hello apm32\r\n");
    //按键初始化
    init_key_btn();
    while (1)
    {
        Delay(0x2FFFFF);
        led_toggle(LED0);
        led_toggle(LED1);
        //按键事件循环调用
        key_lib_buttons_process();
            
    }
}

 

main.c 调用

 

最新回复

按键框架不错! 不过如果是简单的几个按键处理一般就用个任务就完成了。 懒得整那么复杂。   详情 回复 发表于 2023-6-1 09:16
点赞(1) 关注
 
 

回复
举报

6587

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

代码中按键消抖是怎么进行的呢

 
 
 

回复

6841

帖子

11

TA的资源

版主

板凳
 
贴上来的代码,可以整理一下,点空格太多了。
 
 
 

回复

6069

帖子

4

TA的资源

版主

4
 

按键框架不错!

不过如果是简单的几个按键处理一般就用个任务就完成了。 懒得整那么复杂。

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表