本文主要是介绍12. 定时器按键消抖,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
12. 定时器按键消抖
- 定时器按键消抖简介
- 定时器消抖配置步骤
- 程序编写
- bsp_keyfilter.h
- bsp_keyfilter.c
- main
定时器按键消抖简介
使用延时函数消抖会浪费 CPU 性能,因为延时函数就是空跑。如果按键是使用中断的方式实现的,就更不能在中断服务函数中使用延时函数,因为中断服务函数最基本的要求就是快进快出。 所以可以使用定时器设置好时间,就可以去跑其他的进程,当时间到了,就会触发中断,然后在中断函数中做相应的处理。
需要在图中t1 ~ t3 这个时间段消抖。设置按键为下降沿触发,因此会在t1、t2和t3这3个时刻会触发按键中断,每次进入中断处理函数都会重新开启定时器中断。但是t1 ~ t2 和 t2 ~ t3 这两个时间段是小于设定的定时器时间,所以虽然 t1 开启了定时器,但是定时器定时器时间还没到,就重置了定时器,最终只有t3时刻开启的定时器能完整的完成整个定时器周期并触发中断
定时器消抖配置步骤
- 配置按键 IO 中断
配置按键所使用的 IO,因为要使用到中断驱动按键,所以要配置 IO 的中断模式 - 初始化消抖用的定时器
- 编写中断处理函数
需要两个中断处理函数:按键对应的 GPIO 中断处理函数和 EPIT1 定时器的中断处理函数。按键中断处理函数主要是开启定时器。
程序编写
bsp_keyfilter.h
#pragma once
void filterkey_init();
void filtertimer_init(unsigned int value);
void filtertimer_stop();
void filtertimer_restart(unsigned int value);
void filtertimer_irqhandler();
void gpio1_16_31_irqhandler();
bsp_keyfilter.c
#include "bsp_key.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_beep.h"
#include "bsp_keyfilter.h"void fileterkey_init()
{gpio_pin_config_t key_config;// 1. 初始化 IOIOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xF080);// 2. 初始化 GPIO 为中断key_config.direction = kGPIO_DigitalInput;key_config.interruptMode = kGPIO_IntFallingEdge;key_config.outputLogic = 1;gpio_init(GPIO1, 18, &key_config);// 使能 GPIO 中断,并且注册中断处理函数GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);system_register_irqhandler(GPIO1_Combined_16_31_IRQn,(system_irq_handler_t)gpio1_16_31_irqhandler,NULL);gpio_enableint(GPIO1, 18);// 使能GPIO1_IO18中断filetertimer_init(66000000/100);// 初始化定时器10ms
}/** @description : 初始化用于消抖的定时器,默认关闭定时器* @param - value : 定时器EPIT计数值* @return : 无*/
void filtertimer_init(unsigned int value)
{EPIT1->CR = 0; //先清零/** CR寄存器:* bit25:24 01 时钟源选择Peripheral clock=66MHz* bit15:4 0 1分频* bit3: 1 当计数器到0的话从LR重新加载数值* bit2: 1 比较中断使能* bit1: 1 初始计数值来源于LR寄存器值* bit0: 0 先关闭EPIT1*/EPIT1->CR = (1<<24 | 1<<3 | 1<<2 | 1<<1);/* 计数值 */EPIT1->LR = value;/* 比较寄存器,当计数器值和此寄存器值相等的话就会产生中断 */EPIT1->CMPR = 0; GIC_EnableIRQ(EPIT1_IRQn); /* 使能GIC中对应的中断 *//* 注册中断服务函数 */system_register_irqhandler(EPIT1_IRQn, (system_irq_handler_t)filtertimer_irqhandler, NULL);
}void filtertimer_stop(void)
{EPIT1->CR &= ~(1<<0); /* 关闭定时器 */
}/** @description : 重启定时器* @param - value : 定时器EPIT计数值* @return : 无*/
void filtertimer_restart(unsigned int value)
{EPIT1->CR &= ~(1<<0); /* 先关闭定时器 */EPIT1->LR = value; /* 计数值 */EPIT1->CR |= (1<<0); /* 打开定时器 */
}void filtertimer_irqhandler(void)
{ static unsigned char state = OFF;if(EPIT1->SR & (1<<0)) // 判断比较事件是否发生{filtertimer_stop(); // 关闭定时器if(gpio_pinread(GPIO1, 18) == 0) // KEY0 {state = !state;beep_switch(state); // 反转蜂鸣器 }}EPIT1->SR |= 1<<0; // 清除中断标志位
}void gpio1_16_31_irqhandler(void)
{ // 开启定时器filtertimer_restart(66000000/100);// 清除中断标志位gpio_clearintflags(GPIO1, 18);
}
main
int main(void)
{unsigned char state = OFF;int_init(); // 初始化中断(一定要最先调用)imx6u_clkinit(); clk_enable(); led_init(); beep_init(); filterkey_init(); while(1) { state = !state;led_switch(LED0, state);delay(500);}return 0;
}
这篇关于12. 定时器按键消抖的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!