stm32按键检测(状态机加定时器中断)(STM32F103ZET6 + 固件库)

        普通的按键在触发时总会有5~10ms的抖动,在主循环内检测按键和直接使用中断都需要延时消抖,对正常的程序执行产生一定影响,在这里使用状态机加定时器中断的方式来实现stm32按键的检测。

一、GPIO,定时器和中断配置

        我使用的板子按键连接在A0、E2、E3、E4这四个IO口上,因此我初始化GPIOA和GPIOE这两个GPIO口,TIM6是一个基本定时器,只有基本的定时功能,在这里用来实现按键的定时检测。

void KEY_Init(void)
{
    //结构体定义
    GPIO_InitTypeDef GPIO_KEY_InitStrctural;
    TIM_TimeBaseInitTypeDef TIM_BASEInitStructural;
    NVIC_InitTypeDef NVIC_InitStructural;
    //GPIO和定时器时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

    //IO口配置,我A0口的按键接VCC,因此初始化为下拉输入,其他按键接GND,初始化为上拉输入
    GPIO_KEY_InitStrctural.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_KEY_InitStrctural.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA, &GPIO_KEY_InitStrctural);
    GPIO_KEY_InitStrctural.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_KEY_InitStrctural.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
    GPIO_Init(GPIOE, &GPIO_KEY_InitStrctural);

    //定时器配置,10ms进一次中断
    TIM_BASEInitStructural.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_BASEInitStructural.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_BASEInitStructural.TIM_Period = 100-1;
    TIM_BASEInitStructural.TIM_Prescaler = 7200-1;
    TIM_TimeBaseInit(TIM6, &TIM_BASEInitStructural);

    //定时器中观使能和中断标志位清零
    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
    TIM_ClearITPendingBit(TIM6, TIM_IT_Update);

    //NVIC配置,优先级可以自己修改
    NVIC_InitStructural.NVIC_IRQChannel = TIM6_IRQn;
    NVIC_InitStructural.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructural.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructural.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructural);
    
    //定时器使能
    TIM_Cmd(TIM6, ENABLE);
}

二、按键检测函数的实现

        这里在按键松开的时候将按键值返回,想要修改成按下时返回按键值在第二个case中对按键值判断完毕后直接返回就可以了

static uint8_t KEY_Get_Num(void)
{
    enum {
        KEY_STATE_INIT,
        KEY_STATE_WAIT_RELEASE,
        KEY_STATE_RELEASE
        };
    
    static uint8_t KEY_State = KEY_STATE_INIT;
    static uint8_t key_return = NO_KEY_PRESS;
    
    switch(KEY_State)
    {
        case KEY_STATE_INIT:
            //有一个按键按下就进入等待按键松开状态
            if(KEY_WK_UP || !KEY1 || !KEY2 || !KEY3)
                KEY_State = KEY_STATE_WAIT_RELEASE;
        break;
        case KEY_STATE_WAIT_RELEASE:
            //这些具体的按键含义都在头文件定义,头文件在文章最后
            if(KEY_WK_UP)
                key_return = KEY_WK_UP_PRESS;
            else if(!KEY1)
                key_return = KEY1_PRESS;
            else if(!KEY2)
                key_return = KEY2_PRESS;
            else if(!KEY3)
                key_return = KEY3_PRESS;
            else
                key_return = NO_KEY_PRESS;
            KEY_State = KEY_STATE_RELEASE;
        break;
        case KEY_STATE_RELEASE:
            //按键都不按下
            if(!(KEY_WK_UP) && KEY1 && KEY2 && KEY3)
            {
                KEY_State = KEY_STATE_INIT;
                return key_return;
            }
        break;
    }
    
    return 0;
}

三、按键返回函数和中断处理函数

        我们定义一个全局变量"key_num"用来保存要返回给主函数的按键值,在中断处理函数中调用按键检测函数获得按键值,将它赋给"key_num",在主函数中就可以调用按键返回函数来获得是哪个按键按下了

(1)按键返回函数
uint8_t key(void)
{
    return key_num;
}
(2)中断处理函数
void TIM6_IRQHandler(void)
{
//判断中断标志位
    if(TIM_GetITStatus(TIM6, TIM_IT_Update))
        key_num = KEY_Get_Num();
//清理标志位,确保不会错误的进入中断
    TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}

四、.h文件编写

#ifndef __KEY_H
#define __KEY_H

//这里使用宏对位带进行封装,编译操作
#define KEY_WK_UP      PAIn(0)
#define KEY1          PEIn(4)
#define KEY2          PEIn(3)
#define KEY3          PEIn(2)

#define KEY1_PRESS          1
#define KEY2_PRESS          2
#define KEY3_PRESS          3
#define KEY_WK_UP_PRESS     4
#define NO_KEY_PRESS        0

//函数声明,在主函数中调用
void KEY_Init(void);
uint8_t key(void);

#endif

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值