按键的基本原理是设置单片机IO口(PB0-PB3)为输入状态,如DDRB = 0XF0(方向寄存器,“1”为输出,“0”为输入);
单片机一直检测按键端口(PB0-PB3)的状态,当端口为低电平时(即按键按下),实行相应的动作(比如控制LED灯)。
原理就是这么回事,但是正真实现时,按键会有抖动,要进行按键去抖,下图为按键按下时的抖动图。
按键实行一个动作过程是需要一定时间的,一般为100mS-1S左右,而一个单片机执行一个机器周期的时间很短,时钟为10MH的周期为0.1μs,这样按键每一次动作程序就会多次检测按键,出现误判(一次按下,多次动作)。
代码将讲解如何实现按键扫描功能,注册按键事件(单击/双击/长按/长长按/按下/松开)
/********************************************************************************
* @file bsp_key.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-10-10
* @brief NULL
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include #include #include #include "RTE_Components.h" #include CMSIS_device_header #include "bsp_gpio.h" #include "bsp_exti.h" #include "bsp_led.h" #include "bsp_key.h" /* Private Includes ----------------------------------------------------------*/ #include "business_gpio.h" #include "business_function.h" /* Private Define ------------------------------------------------------------*/ /* Private Variables ---------------------------------------------------------*/ #if (BS_BUTTON_NUM != 0) static const bsp_gpio_t g_gpio_init[BS_BUTTON_NUM] = { #if (BS_BUTTON_NUM > 0) {BS_BUTTON0_GPIO_PORT, BS_BUTTON0_PIN, BS_BUTTON0_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON0_PULL, BS_BUTTON0_EXTI_SEL, BS_BUTTON0_EXTI_IRQn, BS_BUTTON0_EXTI_EDGE_LEVEL_SEL, BS_BUTTON0_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 1) {BS_BUTTON1_GPIO_PORT, BS_BUTTON1_PIN, BS_BUTTON1_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON1_PULL, BS_BUTTON1_EXTI_SEL, BS_BUTTON1_EXTI_IRQn, BS_BUTTON1_EXTI_EDGE_LEVEL_SEL, BS_BUTTON1_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 2) {BS_BUTTON2_GPIO_PORT, BS_BUTTON2_PIN, BS_BUTTON2_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON2_PULL, BS_BUTTON2_EXTI_SEL, BS_BUTTON2_EXTI_IRQn, BS_BUTTON2_EXTI_EDGE_LEVEL_SEL, BS_BUTTON2_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 3) {BS_BUTTON3_GPIO_PORT, BS_BUTTON3_PIN, BS_BUTTON3_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON3_PULL, BS_BUTTON3_EXTI_SEL, BS_BUTTON3_EXTI_IRQn, BS_BUTTON3_EXTI_EDGE_LEVEL_SEL, BS_BUTTON3_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 4) {BS_BUTTON4_GPIO_PORT, BS_BUTTON4_PIN, BS_BUTTON4_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON4_PULL, BS_BUTTON4_EXTI_SEL, BS_BUTTON4_EXTI_IRQn, BS_BUTTON4_EXTI_EDGE_LEVEL_SEL, BS_BUTTON4_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 5) {BS_BUTTON5_GPIO_PORT, BS_BUTTON5_PIN, BS_BUTTON5_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON5_PULL, BS_BUTTON5_EXTI_SEL, BS_BUTTON5_EXTI_IRQn, BS_BUTTON5_EXTI_EDGE_LEVEL_SEL, BS_BUTTON5_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 6) {BS_BUTTON6_GPIO_PORT, BS_BUTTON6_PIN, BS_BUTTON6_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON6_PULL, BS_BUTTON6_EXTI_SEL, BS_BUTTON6_EXTI_IRQn, BS_BUTTON6_EXTI_EDGE_LEVEL_SEL, BS_BUTTON6_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 7) {BS_BUTTON7_GPIO_PORT, BS_BUTTON7_PIN, BS_BUTTON7_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON7_PULL, BS_BUTTON7_EXTI_SEL, BS_BUTTON7_EXTI_IRQn, BS_BUTTON7_EXTI_EDGE_LEVEL_SEL, BS_BUTTON7_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 8) {BS_BUTTON8_GPIO_PORT, BS_BUTTON8_PIN, BS_BUTTON8_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON8_PULL, BS_BUTTON8_EXTI_SEL, BS_BUTTON8_EXTI_IRQn, BS_BUTTON8_EXTI_EDGE_LEVEL_SEL, BS_BUTTON8_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 9) {BS_BUTTON9_GPIO_PORT, BS_BUTTON9_PIN, BS_BUTTON9_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON9_PULL, BS_BUTTON9_EXTI_SEL, BS_BUTTON9_EXTI_IRQn, BS_BUTTON9_EXTI_EDGE_LEVEL_SEL, BS_BUTTON9_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 10) {BS_BUTTON10_GPIO_PORT, BS_BUTTON10_PIN, BS_BUTTON10_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON10_PULL, BS_BUTTON10_EXTI_SEL, BS_BUTTON10_EXTI_IRQn, BS_BUTTON10_EXTI_EDGE_LEVEL_SEL, BS_BUTTON10_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 11) {BS_BUTTON11_GPIO_PORT, BS_BUTTON11_PIN, BS_BUTTON11_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON11_PULL, BS_BUTTON11_EXTI_SEL, BS_BUTTON11_EXTI_IRQn, BS_BUTTON11_EXTI_EDGE_LEVEL_SEL, BS_BUTTON11_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 12) {BS_BUTTON12_GPIO_PORT, BS_BUTTON12_PIN, BS_BUTTON12_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON12_PULL, BS_BUTTON12_EXTI_SEL, BS_BUTTON12_EXTI_IRQn, BS_BUTTON12_EXTI_EDGE_LEVEL_SEL, BS_BUTTON12_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 13) {BS_BUTTON13_GPIO_PORT, BS_BUTTON13_PIN, BS_BUTTON13_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON13_PULL, BS_BUTTON13_EXTI_SEL, BS_BUTTON13_EXTI_IRQn, BS_BUTTON13_EXTI_EDGE_LEVEL_SEL, BS_BUTTON13_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 14) {BS_BUTTON14_GPIO_PORT, BS_BUTTON14_PIN, BS_BUTTON14_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON14_PULL, BS_BUTTON14_EXTI_SEL, BS_BUTTON14_EXTI_IRQn, BS_BUTTON14_EXTI_EDGE_LEVEL_SEL, BS_BUTTON14_EXTI_RISE_FALL_SEL}, #endif #if (BS_BUTTON_NUM > 15) {BS_BUTTON15_GPIO_PORT, BS_BUTTON15_PIN, BS_BUTTON15_GPIO_CLK, BSP_GPIO_PIN_SET, BS_BUTTON15_PULL, BS_BUTTON15_EXTI_SEL, BS_BUTTON15_EXTI_IRQn, BS_BUTTON15_EXTI_EDGE_LEVEL_SEL, BS_BUTTON15_EXTI_RISE_FALL_SEL}, #endif }; /* External Variables --------------------------------------------------------*/ typedef void(*bsp_button_callback)(void); static bsp_button_callback irq_callback[BS_BUTTON_NUM] = {0}; /* Private Macro -------------------------------------------------------------*/ static void bsp_button_exti_callback(void *gpiox, uint16_t gpio_pin); /* Public Function Prototypes -----------------------------------------------*/ /** * @brief [初始化] 按键引脚初始化并注册按键外部中断回调函数 */ void bsp_button_init(void) { uint8_t ch; for (ch = 0; ch < BS_BUTTON_NUM; ch++) { /* Enable the BUTTON Clock */ bsp_gpio_set_clk(GPIO_APBx, g_gpio_init[ch].periph, true); if (g_gpio_init[ch].is_exti == DISABLE) { /* Configure Button pin as input */ bsp_gpio_init_input(g_gpio_init[ch].port, g_gpio_init[ch].pin, g_gpio_init[ch].pull); } else { /* Configure Button pin as input with External interrupt */ irq_callback[ch] = NULL; bsp_gpio_init_input_exit(g_gpio_init[ch].port, g_gpio_init[ch].pin, g_gpio_init[ch].irqn, g_gpio_init[ch].exti_type, g_gpio_init[ch].exti_event, g_gpio_init[ch].pull); } } if (BS_BUTTON_NUM) { bsp_gpio_exit_irq_register_callback(bsp_button_exti_callback); } } /** * @brief [反初始化] 按键恢复默认状态 * @param ch: 按键号 */ void bsp_button_deinit(bsp_button_t ch) { bsp_gpio_deinit(g_gpio_init[ch].port, g_gpio_init[ch].pin); } /** * @brief 设置按键中断优先级(强制配置为低优先级) * @param ch: 按键号 */ void bsp_button_set_irq(bsp_button_t ch) { bsp_exit_set(g_gpio_init[ch].irqn, 3); } /** * @brief 清除按键中断优先级 * @param ch: 按键号 */ void bsp_button_clear_irq(bsp_button_t ch) { bsp_exit_clear_set(g_gpio_init[ch].irqn); } /** * @brief 得到按键状态 * @param ch: 按键号 * @retval 0 -- 低电平, 1 -- 高电平 */ bool bsp_button_get_state(bsp_button_t ch) { return (bool)bsp_gpio_get_state(g_gpio_init[ch].port, g_gpio_init[ch].pin); } /** * @brief 注册按键中断的回调函数 * @param ch: 键号 * @param event: 绑定中断回调事件 * @retval 0--失败 1--成功 */ bool bsp_button_irq_callback(bsp_button_t ch, void *event) { if (irq_callback[ch] != NULL) { return false; } else { irq_callback[ch] = (bsp_button_callback)event; } return true; } /** * @brief 用于外部中断服务回调,并执行对应引脚的事件 * @param gpiox: - * @param gpio_pin: 引脚号 */ static void bsp_button_exti_callback(void *gpiox, uint16_t gpio_pin) { #if BS_BUTTON_NUM > 0 if (gpio_pin == BS_BUTTON0_PIN && irq_callback[BSP_BUTTON_X_0] != NULL) { if (irq_callback[BSP_BUTTON_X_0]) { irq_callback[BSP_BUTTON_X_0](); } } #endif #if BS_BUTTON_NUM > 1 else if (gpio_pin == BS_BUTTON1_PIN && irq_callback[BSP_BUTTON_X_1] != NULL) { if (irq_callback[BSP_BUTTON_X_1]) { irq_callback[BSP_BUTTON_X_1](); } } #endif #if BS_BUTTON_NUM > 2 else if (gpio_pin == BS_BUTTON2_PIN && irq_callback[BSP_BUTTON_X_2] != NULL) { if (irq_callback[BSP_BUTTON_X_2]) { irq_callback[BSP_BUTTON_X_2](); } } #endif #if BS_BUTTON_NUM > 3 else if (gpio_pin == BS_BUTTON3_PIN && irq_callback[BSP_BUTTON_X_3] != NULL)
上一篇:[单片机框架][bsp层][AT32F415][bsp_adc] adc配置和使用
下一篇:[单片机框架][bsp层][AT32F415][bsp_led] LED配置和使用
推荐阅读最新更新时间:2024-11-12 09:44