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[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 调用