微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > stm32中断按键去抖

stm32中断按键去抖

时间:10-02 整理:3721RD 点击:
今天使用按键进中断,发现自己去抖做的不是很好,大家有什么好的方法吗,最好是软件上的,我是进去之后等待了大约10us,然后再检测一下,引脚电平,如果是低电平就继续操作,否则不操作。(我设置的中断触发方式是下降沿触发)。
但是效果不是特别好。

用我这个吧,调试好的已经,按键不占用程序时间,只检测状态,在中断中运行
define _KEY_BOARD_C
#include"delay.h"
#include"key.h"
#include"main.h"
u8 KeySta[3] = {1,1,1}; //当前按键状态
u8 KeyCodeMaps[3] = {
        '1','2','3'
};
void KeyInit(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能其时钟
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//输入上拉
        GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化按键端口PC2,3,5;
}
void KeyDriver(void)
{
        static u8 backup[3] = {1,1,1}; //按键值备份,保存前一次的值
        u8 i = 0;
        for(i = 0; i < 3; i++)
        {
                if(KeySta[i] != backup[i])
                {
                        if(backup[i] == 0)
                        {
                                KeyAction(KeyCodeMaps[i]);
                        }
                        backup[i] = KeySta[i];
                }       
        }
}
void KeyAction(u8 keycode)
{
        if(keycode == '1')
        {
                                       
        }
        else if(keycode == '2')
        {
               
        }
        else if(keycode == '3')
        {
                       
        }
}
/*******************************************************************************
* 文件名:void TIMX_Configuration(u16 arr,u16 psc)
* 描  述: 定时器3初始化配置函数
* 功  能:刷新
* 作  者:大核桃
* 版本号:1.0.1(2015.03.03)
*******************************************************************************/
/*计算中断时间,计算公式如下:
*Tout= ((arr+1)*(psc+1))/Tclk;
*其中:
*Tclk:TIM3 的输入时钟频率(单位为 Mhz)72MHz
*Tout:TIM3 溢出时间(单位为 us)
*/
void TIM3_Configuration(u16 arr,u16 psc)//通用定时器(2,3,4,5)的配置函数
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,ENABLE);//使能定时器3,APB1PeriphClock
        //定时器 TIM3 初始化
        TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载寄存器周期的值
        TIM_TimeBaseStructure.TIM_Prescaler = psc;//设置时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_div1; //设置时钟分割
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //②初始化 TIM3
        TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //③允许更新中断
        TIM_Cmd(TIM3, ENABLE); //⑤使能 TIM3
                       
}
void KeyScan(void)
{
        static u8 keybuf[3] = {0xFF,0XFF,0XFF}; //按键扫描缓冲区,保存一段时间内的扫描值
        u8 i = 0;
        keybuf[0] = (keybuf[0] << 1) | KEY1;
        keybuf[1] = (keybuf[1] << 1) | KEY2;
        keybuf[2] = (keybuf[2] << 1) | KEY3;
        for(i = 0; i< 3; i++)
        {
                if(keybuf[i] == 0x00)
                {
                        KeySta[i] = 0;
                }
                else if(keybuf[i] == 0XFF)
                {
                        KeySta[i] = 1;
                }
                else
                {
                       
                }       
        }       
}
/*******************************************************************************
* 文件名:void TIM3_NVIC_Config(void)
* 描  述: 定时器3中断优先级管理
* 功  能:刷新
* 作  者:大核桃
* 版本号:1.0.1(2015.03.03)
*******************************************************************************/
void TIM3_NVIC_Config(void)
{       
        NVIC_InitTypeDef NVIC_InitStructure;
        //通用定时器(2,3,4,5)中断优先级 NVIC 设置
        NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 0 级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级1级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
        NVIC_Init(&NVIC_InitStructure); //④初始化 NVIC 寄存器                               
}
/*******************************************************************************
* 文件名:定时器3中断服务函数
* 描  述:
* 功  能:刷新
* 作  者:大核桃
* 版本号:1.0.1(2015.03.03)
*******************************************************************************/
void TIM3_IRQHandler(void) //TIM3 中断
{
        if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
        {
                KeyScan();
                TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除 TIM3 更新中断标志
        }
}

呵呵,大核桃!
你确定用定时扫描好?
我要是按住不放呢!

按键滤波采用定时扫描还是比较好的,可以不用delay了,只是每次按键扫描时间到设置一个变量标志++,可以解决长按还有按键处于什么状态执行的问题

可以使用SYSTick定时器代替TIM3吗?这样可以省一个定时器出来呢,呵呵

你想做长按键也可以啊,这个程序

你可以试试,呵呵,我没弄过

所问问题好了吗?

我感觉我采纳的那个就行了,我这段没弄这个

谢谢分享学习一下

这个比延时的要好高明的多,以前也看过一篇类似的文章,写的很经典!

谢谢分享学习一下

其实是占程序时间的,只不过是在中断中占用了。
这种方法又叫连续扫描法,没有延时函数,利用计数器延时判断。但是这种方法在主程序需要连续采样转换的时候不合适。因为中断会打断采样转换的连续性。
当主程序需要死循环连续采样不能间断的时候,就适合按键用外部中断触发。因为平时不用按键,主程序可以连续运行,只有调试的时候才使用按键。如果使用定时器中断查询按键,你想想程序还能工作吗?

点到他的穴了

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top