STM32-定时器实现按键检测(多按键短按)

前言

由于最近做stm32项目用到按键的功能,目前常见的按键检测程序都是在主函数中使用delay延时来实现按键消抖的,但是这样简单粗暴的延时比较占用CPU的资源,影响主函数中其他的功能实现,经过这几天的搜索找到一种利用定时器来实现按键消抖扫描的方法。

实现思路

这篇文章实现的是多个按键(两个)短按功能,具体思路是在定时器中断中10ms扫描一下按键,实现不占CPU资源的按键消抖,主要参考了这篇文章【stm32单片机基础】按键状态机实现长按和短按,讲的很详细,感兴趣的可以去看下。

代码

下面直接贴出代码,bsp_key.c中的相关代码

按键扫描函数

typedef enum
{
    KEY_CHECK =0,//检测
    KEY_CONFIRM = 1,//确认
    KEY_RELEASE = 2//释放
}KEY_STATE;

KEY_STATE KeyState = KEY_CHECK;     //初始化按键状态为检测状态
uint8_t KeyFlag = 0;    //按键标志

void Key_Scan(void)
{
    switch(KeyState)
    {
        case KEY_CHECK:
            if(!KEY)//如果按键值为0,说明按键被按下,切换状态
            {
                KeyState = KEY_CONFIRM;
            }
            break;
        case KEY_CONFIRM:
            if(!KEY)//判断当前按键值是否为0,确认是否按下
            {
                KeyState = KEY_RELEASE;
                if(0 == KEY0)//KEY0被按下
                {
                    KeyFlag = KEY0_PRES;
                }
                if(0 == KEY1)//KEY1被按下
                {
                    KeyFlag = KEY1_PRES;
                }
            }
            else//按键没有被按下,返回上一状态
            {
                KeyState = KEY_CHECK;
            }
            break;
        case KEY_RELEASE:
            if(KEY)//当前按键值为1,说明按键已经释放,切换到开始状态
            {
                KeyState = KEY_CHECK;
            }
            break;
        default:
            break;
    }
}

定时器相关函数

主要包括通用定时器的配置(我这里使用了TIM2)和定时器中断10ms扫描一次按键状态

/*定时器配置*/
void TIMER_Config()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_InternalClockConfig(TIM2);
    TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStruct;
    TIM_TimeBase_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBase_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
    /*定时10ms*/
    TIM_TimeBase_InitStruct.TIM_Period = 100 -1 ;
    TIM_TimeBase_InitStruct.TIM_Prescaler = 7200 - 1;
    TIM_TimeBase_InitStruct.TIM_RepetitionCounter = 0 ;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBase_InitStruct);
    
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    /*TIMER中断配置*/
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    NVIC_InitTypeDef Nvic_InitStruct;
    Nvic_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
    Nvic_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    Nvic_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    Nvic_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&Nvic_InitStruct);
    TIM_Cmd(TIM2, ENABLE);
}

/*定时器中断函数*/
void TIM2_IRQHandler()//10ms进入一次中断,按键扫描
{
    static uint8_t cnt;
    if(TIM_GetFlagStatus(TIM2, TIM_IT_Update) != RESET)//定时中断是否发生
    {   
        Key_Scan();
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除中断标志
    }
}

bsp_key.h的相关代码

#define KEY0    GPIO_ReadInputDataBit(KEY0_GPIO_PORT, KEY0_GPIO_PIN)
#define KEY1    GPIO_ReadInputDataBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN)
#define KEY     ((KEY0) && (KEY1))
#define KEY0_PRES 1
#define KEY1_PRES 2

void KEY_Init(void);    /*按键初始化函数*/
void Key_Scan(void);    /*按键扫描函数*/
void TIMER_Config();    /*定时器配置*/

main.c中的代码

while(1)
    {
        switch(KeyFlag)
        {
            case KEY0_PRES:
				/*
				*在这里插入自己的功能代码
				*/
                KeyFlag = 0;//注意按键标志清零,防止程序跑飞
                break;
            case KEY1_PRES:
                /*
				*在这里插入自己的功能代码
				*/
                KeyFlag = 0;
                break;
            default:
                break;
        }
可以利用 STM32定时器和外部中断实现按键扫描。具体步骤如下: 1. 定义定时器和外部中断的初始化参数。 ``` TIM_HandleTypeDef htim2; TIM_OC_InitTypeDef sConfigOC; GPIO_InitTypeDef GPIO_InitStruct; EXTI_HandleTypeDef hexti; ``` 2. 初始化定时器和外部中断。 ``` void MX_TIM2_Init(void) { htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 1000; //设定定时器计数周期为1ms htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } } void MX_GPIO_Init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; //下降沿触发 GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { //按键被按下 } } ``` 3. 启动定时器和外部中断。 ``` HAL_TIM_Base_Start_IT(&htim2); //启动定时器 HAL_NVIC_EnableIRQ(EXTI0_IRQn); //启动外部中断 ``` 4. 在定时器的中断回调函数中进行按键扫描。 ``` void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &htim2) { static uint16_t key_state = 0; //按键状态,0为未按下,1为按下 if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) //按键被按下 { if (key_state == 0) //如果之前未按下 { key_state = 1; HAL_GPIO_EXTI_Callback(GPIO_PIN_0); //调用外部中断回调函数 } } else //按键未被按下 { key_state = 0; } } } ``` 这样就可以实现按键扫描了。需要注意的是,如果有按键,可以在中断回调函数中根据不同的 GPIO_Pin 进行区分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值