打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

按键的基本原理是设置单片机IO口(PB0-PB3)为输入状态,如DDRB = 0XF0(方向寄存器,“1”为输出,“0”为输入);

单片机一直检测按键端口(PB0-PB3)的状态,当端口为低电平时(即按键按下),实行相应的动作(比如控制LED灯)。

原理就是这么回事,但是正真实现时,按键会有抖动,要进行按键去抖,下图为按键按下时的抖动图。

按键实行一个动作过程是需要一定时间的,一般为100mS-1S左右,而一个单片机执行一个机器周期的时间很短,时钟为10MH的周期为0.1μs,这样按键每一次动作程序就会多次检测按键,出现误判(一次按下,多次动作)。

代码将讲解如何实现按键扫描功能,注册按键事件(单击/双击/长按/长长按/按下/松开)
[单片机框架][APP_KEY] 利用软定时器实现按键扫描

/********************************************************************************
* @file    bsp_key.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-10-10
* @brief   NULL
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

#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)
    {
        if (irq_callback[BSP_BUTTON_X_3])
        {
            irq_callback[BSP_BUTTON_X_3]();
        }
    }
#endif
#if BS_BUTTON_NUM > 4
    else if (gpio_pin == BS_BUTTON4_PIN && irq_callback[BSP_BUTTON_X_4] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_4])
        {
            irq_callback[BSP_BUTTON_X_4]();
        }
    }
#endif
#if BS_BUTTON_NUM > 5
    else if (gpio_pin == BS_BUTTON5_PIN && irq_callback[BSP_BUTTON_X_5] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_5])
        {
            irq_callback[BSP_BUTTON_X_5]();
        }
    }
#endif
#if BS_BUTTON_NUM > 6
    else if (gpio_pin == BS_BUTTON6_PIN && irq_callback[BSP_BUTTON_X_6] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_6])
        {
            irq_callback[BSP_BUTTON_X_6]();
        }
    }
#endif
#if BS_BUTTON_NUM > 7
    else if (gpio_pin == BS_BUTTON7_PIN && irq_callback[BSP_BUTTON_X_7] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_7])
        {
            irq_callback[BSP_BUTTON_X_7]();
        }
    }
#endif
#if BS_BUTTON_NUM > 8
    else if (gpio_pin == BS_BUTTON8_PIN && irq_callback[BSP_BUTTON_X_8] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_8])
        {
            irq_callback[BSP_BUTTON_X_8]();
        }
    }
#endif
#if BS_BUTTON_NUM > 9
    else if (gpio_pin == BS_BUTTON9_PIN && irq_callback[BSP_BUTTON_X_9] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_9])
        {
            irq_callback[BSP_BUTTON_X_9]();
        }
    }
#endif
#if BS_BUTTON_NUM > 10
    else if (gpio_pin == BS_BUTTON10_PIN && irq_callback[BSP_BUTTON_X_10] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_10])
        {
            irq_callback[BSP_BUTTON_X_10]();
        }
    }
#endif
#if BS_BUTTON_NUM > 11
    else if (gpio_pin == BS_BUTTON11_PIN && irq_callback[BSP_BUTTON_X_11] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_11])
        {
            irq_callback[BSP_BUTTON_X_11]();
        }
    }
#endif
#if BS_BUTTON_NUM > 12
    else if (gpio_pin == BS_BUTTON12_PIN && irq_callback[BSP_BUTTON_X_12] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_12])
        {
            irq_callback[BSP_BUTTON_X_12]();
        }
    }
#endif
#if BS_BUTTON_NUM > 13
    else if (gpio_pin == BS_BUTTON13_PIN && irq_callback[BSP_BUTTON_X_13] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_13])
        {
            irq_callback[BSP_BUTTON_X_13]();
        }
    }
#endif
#if BS_BUTTON_NUM > 14
    else if (gpio_pin == BS_BUTTON14_PIN && irq_callback[BSP_BUTTON_X_14] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_14])
        {
            irq_callback[BSP_BUTTON_X_14]();
        }
    }
#endif
#if BS_BUTTON_NUM > 15
    else if (gpio_pin == BS_BUTTON15_PIN && irq_callback[BSP_BUTTON_X_15] != NULL)
    {
        if (irq_callback[BSP_BUTTON_X_15])
        {
            irq_callback[BSP_BUTTON_X_15]();
        }
    }
#endif
}

#else
void bsp_button_init(void)
{
}

void bsp_button_deinit(bsp_button_t ch)
{
}

bool bsp_button_get_state(bsp_button_t ch)
{
    return false;
}

bool bsp_button_irq_callback(bsp_button_t ch, void *event)
{
    return false;
}

void bsp_button_exti_callback(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
}
#endif

/********************************************************************************
* @file    bsp_key.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-03
* @brief   bsp key
********************************************************************************/

#ifndef __BSP_KEY_H
#define __BSP_KEY_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

/* Public enum ---------------------------------------------------------------*/
typedef enum
{
    BSP_BUTTON_X_0 = 0,
    BSP_BUTTON_X_1,
    BSP_BUTTON_X_2,
    BSP_BUTTON_X_3,
    BSP_BUTTON_X_4,
    BSP_BUTTON_X_5,
    BSP_BUTTON_X_6,
    BSP_BUTTON_X_7,
    BSP_BUTTON_X_8,
    BSP_BUTTON_X_9,
    BSP_BUTTON_X_10,
    BSP_BUTTON_X_11,
    BSP_BUTTON_X_12,
    BSP_BUTTON_X_13,
    BSP_BUTTON_X_14,
    BSP_BUTTON_X_15
} bsp_button_t;

typedef enum
{
    BUTTON_MODE_GPIO = 0,
    BUTTON_MODE_EXTI = 1
} bsp_button_mode_t;

/* Public Function Prototypes ------------------------------------------------*/

void bsp_button_init(void);
void bsp_button_deinit(bsp_button_t ch);

void bsp_button_set_irq(bsp_button_t ch);
void bsp_button_clear_irq(bsp_button_t ch);

bool bsp_button_get_state(bsp_button_t ch);

bool bsp_button_irq_callback(bsp_button_t ch, void *event);

#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(51)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033