chejia12 发表于 2023-7-21 09:35

【极海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

按键实例教程:

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

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

[*]        提供了按键处理按键实例,及如何使用按键框架的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;//时间处理函数
[*]
[*]      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 = {KEY1_BUTTON_GPIO_PORT, KEY2_BUTTON_GPIO_PORT};
[*]//按键pin
[*]const uint16_t BUTTON_PIN = {KEY1_BUTTON_PIN, KEY2_BUTTON_PIN};
[*]//按键port
[*]const uint32_t BUTTON_CLK = {KEY1_BUTTON_GPIO_CLK, KEY2_BUTTON_GPIO_CLK};
[*]//外部中断先名
[*]const EINT_LINE_T BUTTON_EINT_LINE = {KEY1_BUTTON_EINT_LINE, KEY2_BUTTON_EINT_LINE};
[*]//外部中断源分组
[*]const SYSCFG_PORT_T BUTTON_PORT_SOURCE = {KEY1_BUTTON_EINT_PORT_SOURCE, KEY2_BUTTON_EINT_PORT_SOURCE};
[*]//外部中断源pin
[*]const SYSCFG_PIN_T BUTTON_PIN_SOURCE = {KEY1_BUTTON_EINT_PIN_SOURCE, KEY2_BUTTON_EINT_PIN_SOURCE};
[*]////外部中断源中断处理函数
[*]const IRQn_Type BUTTON_IRQn = {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);
[*]​
[*]    /** 配置gpio位输入模式,上拉 */
[*]    GPIO_ConfigStructInit(&GPIO_configStruct);
[*]    GPIO_configStruct.mode = GPIO_MODE_IN;//输入
[*]    GPIO_configStruct.pin = BUTTON_PIN;//PIN
[*]    GPIO_configStruct.pupd= GPIO_PUPD_UP;//上拉
[*]    GPIO_Config(BUTTON_PORT, &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_PIN_SOURCE);
[*]​
[*]      /** Configure Button EINT line中断使能*/
[*]      EINT_configStruct.line = BUTTON_EINT_LINE;
[*]      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, 0x0f, 0x0f);
[*]    }
[*]}
[*]​
[*]/*
[*]    读取按键状态
[*]*/
[*]uint8_t bsp_get_key(uint8_t Button)
[*]{
[*]    return GPIO_ReadInputBit(BUTTON_PORT, BUTTON_PIN);
[*]}
[*]​
[*]​
[*]//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 调用http://bbs.**/data/attachment/forum/202305/29/220824juhliywix1usyzhz.png.thumb.jpg





页: [1]
查看完整版本: 【极海APM32F4xx Tiny】学习笔记03-按键输入+自定义按键框架