一. 按键消抖
在之前的 按键中断实验时,我们讲了如何使用中断的方式驱动按键或GPIO。如果通过中断的方式处理按键的话,按键是需要消抖处理的。
而在之前 按键中断实验中,在中断处理函数中对按键进行消抖,调用了 delay 延时函数。
但是,实际开发中,中断函数中不允许使用 delay 延时函数!!!
因为中断服务函数要快进快出!
按键消抖:通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。
按键消抖的必要性:
为确保 CPU对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。
二. 定时器按键消抖
1. 定时器按键消抖原理
本篇讲一下,按键既要用中断的方式驱动,同时,合理的实现一个按键的消抖处理。我们就使用EPIT定时器来实现按键消抖。这种方法也是 Linux内核中对按键的一个处理方式,Linux内核实现按键消抖也是用的这种方法。
下面通过实际举例说明:
2. 代码实现
(1) 大体工作思路
① 配置按键IO中断,即将按键IO设置为中断模式
② 初始化 EPIT1定时器
③ 实现中断服务函数
④ 实现定时器中断服务函数
(2) 代码实现
在 bsp 文件夹下创建名为 “keyfilter” 的文件夹,然后在 bsp/keyfilter 中新建 bsp_keyfilter.h 和 bsp_keyfilter.c 这两个文件。
bsp_keyfilter.c 文件代码如下:
#include "bsp_key_filter.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_beep.h"
/* keyFilter初始化 */
//将按键IO配置为中断模式
void key_filter_init(void)
{
/*按键的IO初始化 */
gpio_pin_config_t key_config;
//复用为GPIO功能
IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);
//配置电气特性
IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0X1070);
//GPIO初始化
key_config.direction = kGPIO_DigitalInput;
key_config.interruptMode = kGPIO_IntFallingEdge;
gpio_init(GPIO1, 18, &key_config);
//使能GIC控制器
GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
//注册按键中断函数
system_register_irqhandler(GPIO1_Combined_16_31_IRQn, gpio_16_31_irqhandler, NULL);
//设置中断使能(不同于上面的GIC控制器使能)
gpio_interrupt_enable(GPIO1, 18);
/*初始化EPIT1定时器*/
key_epit1_init(66000000/100);
}
/* 初始化EPIT1定时器*/
//reload_value: 定时器计数加载值
void key_epit1_init(unsigned int reload_value)
{
EPIT1->CR = 0;
EPIT1->CR = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 24); //1分频
EPIT1->LR = reload_value;
EPIT1->CMPR = 0; //比较值写0(即定时器reload_value每次与0比较)
//初始化GIC中断
GIC_EnableIRQ(EPIT1_IRQn);
//注册EPIT1定时器中断函数
system_register_irqhandler(EPIT1_IRQn, key_filter_epit1_inter, NULL);
}
/* 中断服务函数 */
void gpio_16_31_irqhandler(unsigned int gicciar, void* param)
{
//开启定时器
restart_epit1(66000000/100); //10ms
//清除IO中断标志位
gpio_clearintflags(GPIO1, 18);
}
/* EPIT1定时器中断服务函数*/
void key_filter_epit1_inter(unsigned int gicciar, void* param)
{
static unsigned char beep_state = OFF;
if((EPIT1->SR) & (1 << 0)) //EPIT1定时器中断是否发生
{
//关闭EPIT1定时器
close_epit1();
beep_state = !beep_state;
beep_switch(beep_state);
}
//清除EPIT1定时器标志位
EPIT1->SR = (1 << 0);
}
/*关闭EPIT1定时器*/
void close_epit1(void)
{
EPIT1->CR &= ~(1 << 0);
}
/* 重启EPIT1定时器 */
void restart_epit1(unsigned int reload_value)
{
EPIT1->CR &= ~(1 << 0);
EPIT1->LR = reload_value;
EPIT1->CR |= (1 << 0);
}
main.c 文件代码如下:
主函数中,添加 按键消抖初始化接口。如下所示:
int main(void)
{
unsigned char led_state = OFF;
int_init(); //中断初始化
imux6ull_clk_init(); //初始化系统时钟
clk_enable(); //使能外设时钟
led_init(); //Led初始化
beep_init(); //蜂鸣器初始化
key_init(); //key按键初始化
key_filter_init();
while(1)
{
led_state = !led_state;
led_switch(LED0, led_state);
delay(500);
}
return 0;
}
以上就是使用 EPIT1定时器实现了按键的消抖。按键IO设置为中断方式,再结合定时器最终实现按键的消抖。
据左大神讲解,Linux 内核中的按键消抖也是这种实现原理。
按键消抖实验就总结到这里。加油!