1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子Linux感兴趣的同学可以加群讨论:935446741 4)关注正点原子公众号,获取最新资料更新
第十九章 定时器按键消抖实验
在第十五章和第十七章实验中都用到了按键,用到按键就要处理因为机械结构带来的按键抖动问题,也就是按键消抖。前面的实验中都是直接使用了延时函数来实现消抖,因为简单,但是直接用延时函数来实现消抖会浪费CPU性能,因为在延时函数里面CPU什么都做不了。如果按键使用中断的话更不能在中断里面使用延时函数,因为中断服务函数要快进快出!本章我们学习如何使用定时器来实现按键消抖,使用定时器既可以实现按键消抖,而且也不会浪费CPU性能,这个也是Linux驱动里面按键消抖的做法。
19.1 定时器按键消抖简介 按键消抖的原理在第十五章已经详细的讲解了,其实就是在按键按下以后延时一段时间再去读取按键值,如果此时按键值还有效那就表示这是一次有效的按键,中间的延时就是消抖的。但是这有一个缺点,就是延时函数会浪费CPU性能,因为延时函数就是空跑。如果按键是用中断方式实现的,那就更不能在中断服务函数里面使用延时函数,因为中断服务函数最基本的要求就是快进快出!上一章我们学习了EPIT定时器,定时器设置好定时时间,然后CPU就可以做其他事情去了,定时时间到了以后就会触发中断,然后在中断中做相应的处理即可。因此,我们可以借助定时器来实现消抖,按键采用中断驱动方式,当按键按下以后触发按键中断,在按键中断中开启一个定时器,定时周期为10ms,当定时时间到了以后就会触发定时器中断,最后在定时器中断处理函数中读取按键的值,如果按键值还是按下状态那就表示这是一次有效的按键。定时器按键消抖如图19.1.1所示:
图19.1.1 定时器消抖示意图 在图19.1.1中t1t3这一段时间就是按键抖动,是需要消除的。设置按键为下降沿触发,因此会在t1、t2和t3这三个时刻会触发按键中断,每次进入中断处理函数都会重新开器定时器中断,所以会在t1、t2和t3这三个时刻开器定时器中断。但是t1t2和t2~t3这两个时间段是小于我们设置的定时器中断周期(也就是消抖时间,比如10ms),所以虽然t1开启了定时器,但是定时器定时时间还没到呢t2时刻就重置了定时器,最终只有t3时刻开启的定时器能完整的完成整个定时周期并触发中断,我们就可以在中断处理函数里面做按键处理了,这就是定时器实现按键防抖的原理,Linux里面的按键驱动用的就是这个原理! 关于定时器按键消抖的原理就介绍到这里,接下来讲解如何使用EPIT1来配合按键KEY来实现具体的消抖,步骤如下: 1、配置按键IO中断 配置按键所使用的IO,因为要使用到中断驱动按键,所以要配置IO的中断模式。 2、初始化消抖用的定时器 上面已经讲的很清楚了,消抖要用定时器来完成,所以需要初始化一个定时器,这里使用上一章讲解的EPIT1定时器,也算是对EPIT1定时器的一次巩固。定时器的定时周期为10ms,也可根据实际情况调整定时周期。 3、编写中断处理函数 需要编写两个中断处理函数:按键对应的GPIO中断处理函数和EPIT1定时器的中断处理函数。在按键的中断处理函数中主要用于开启EPIT1定时器,EPIT1的中断处理函数才是重点,按键要做的具体任务都是在定时器EPIT1的中断处理函数中完成的,比如控制蜂鸣器打开或关闭。 19.2 硬件原理分析 本试验用到的资源如下: ①、一个LED灯LED0。 ②、定时器EPTI1。 ③、一个按键KEY。 ④、一个蜂鸣器。 本试验效果和第十五章的试验效果一样,按下KEY会打开蜂鸣器,再次按下KEY就会关闭蜂鸣器。LED0作为系统提示灯不断的闪烁。 19.3 试验程序编写 本实验对应的例程路径为:开发板光盘-> 1、裸机例程-> 11_key_filter。 本章实验在上一章例程的基础上完成,更改工程名字为“key_filter”,然后在bsp文件夹下创建名为“keyfilter”的文件夹,然后在bsp/keyfilter中新建bsp_keyfilter.c和bsp_keyfilter.h这两个文件。在bsp_keyfilter.h中输入如下内容: 示例代码19.3.1 bsp_keyfilter.h 文件代码
1 #ifndef _BSP_KEYFILTER_H
2 #define _BSP_KEYFILTER_H
3 /***************************************************************
4 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
5 文件名 : bsp_keyfilter.h
6 作者 : 左忠凯
7 版本 : V1.0
8 描述 : 定时器按键消抖驱动头文件。
9 其他 : 无
10 论坛 : www.openedv.com
11 日志 : 初版V1.0 2019/1/5 左忠凯创建
12 ***************************************************************/
13
14 /* 函数声明 */
15 void filterkey_init(void);
16 void filtertimer_init(unsigned int value);
17 void filtertimer_stop(void);
18 void filtertimer_restart(unsigned int value);
19 void filtertimer_irqhandler(void);
20 void gpio1_16_31_irqhandler(void);
21
22 #endif
bsp_keyfilter.h文件很简单,只是函数声明。在bsp_keyfilter.c中输入如下内容:
示例代码19.3.2 bsp_keyfilter.c 文件代码
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_keyfilter.c
作者 : 左忠凯
版本 : V1.0
描述 : 定时器按键消抖驱动。
其他 : 按键采用中断方式,按下按键触发按键中断,在按键中断里面
使能定时器定时中断。使用定时器定时中断来完成消抖延时,
定时器中断周期就是延时时间。如果定时器定时中断触发,
表示消抖完成(延时周期完成),即可执行按键处理函数。
论坛 : www.openedv.com
日志 : 初版V1.0 2019/1/5 左忠凯创建
***************************************************************/
1 #include "bsp_key.h"
2 #include "bsp_gpio.h"
3 #include "bsp_int.h"
4 #include "bsp_beep.h"
5 #include "bsp_keyfilter.h"
6
7 /*
8 * @description : 按键初始化
9 * @param : 无
10 * @return : 无
11 */
12 void filterkey_init(void)
13 {
14 gpio_pin_config_t key_config;
15
16 /* 1、初始化IO */
17 IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);
18 IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xF080);
19
20 /* 2、初始化GPIO为中断 */
21 key_config.direction = kGPIO_DigitalInput;
22 key_config.interruptMode = kGPIO_IntFallingEdge;
23 key_config.outputLogic = 1;
24 gpio_init(GPIO1, 18, &key_config);
25
26 /* 3、 使能GPIO中断,并且注册中断处理函数 */
27 GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
28 system_register_irqhandler(GPIO1_Combined_16_31_IRQn,
(system_irq_handler_t)gpio1_16_31_irqhandler,
NULL);
29
30 gpio_enableint(GPIO1, 18); /* 使能GPIO1_IO18的中断功能 */
31 filtertimer_init(66000000/100); /* 初始化定时器,10ms */
32 }
33
34 /*
35 * @description : 初始化用于消抖的定时器,默认关闭定时器
36 * @param - value : 定时器EPIT计数值
37 * @return : 无
38 */
39 void filtertimer_init(unsigned int value)
40 {
41 EPIT1->CR = 0; /* 先清零 */
42 EPIT1->CR = (1
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?