ARM(I.MX6ULL) EPIT定时器详解定时器按键消抖

Posted 行稳方能走远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARM(I.MX6ULL) EPIT定时器详解定时器按键消抖相关的知识,希望对你有一定的参考价值。

参考:Linux之ARM (I.MX6ULL) EPIT定时器详解
作者:一只青木呀
发布时间: 2020-09-20 10:03:37
网址:https://blog.csdn.net/weixin_45309916/article/details/108689629

参考:Linux驱动中按键消抖原理
作者:一只青木呀
发布时间: 2020-09-20 10:15:32
网址:https://blog.csdn.net/weixin_45309916/article/details/108690002


定时器是最常用的外设,常常需要使用定时器来完成精准的定时功能, I.MX6U 提供了多种硬件定时器,有些定时器功能非常强大。我们从最基本的 EPIT 定时器开始,学习如何配置 EPIT 定时器,使其按照给定的时间,周期性的产生定时器中断,在定时器中断里面我们可以做其它的处理,比如翻转 LED 灯。

1、EPIT定时器简介

EPIT 的全称是: Enhanced Periodic Interrupt Timer,直译过来就是增强的周期中断定时器,它主要是完成周期性中断定时的。学过 STM32 的话应该知道, STM32 里面的定时器还有很多其它的功能,比如输入捕获、 PWM 输出等等但是 I.MX6U 的 EPIT 定时器只是完成周期性中断定时的,仅此一项功能!至于输入捕获、 PWM 输出等这些功能, I.MX6U 由其它的外设来完成(下一节讲的GPT)。

EPIT 是一个 32 位定时器,在处理器几乎不用介入的情况下提供精准的定时中断,软件使能以后 EPIT 就会开始运行, EPIT 定时器有如下特点:

  • ①、时钟源可选的 32 位向下计数器(减1减到0)
  • ②、 12 位的分频值。
  • ③、当计数值和比较值相等的时候产生中断。

EPIT 定时器结构如下图所示:

上图中各部分的功能如下:

  • ①、这是个多路选择器,用来选择 EPIT 定时器的时钟源, EPIT 共有 3 个时钟源可选择,ipg_clk(选这个,66MHz,前面时钟系统配置讲过)、 ipg_clk_32k 和 ipg_clk_highfreq。
  • ②、这是一个 12 位的分频器,负责对时钟源进行分频, 12 位对应的值是 0 ~ 4095,对应着1~4096 分频。
  • ③、经过分频的时钟进入到 EPIT 内部,在 EPIT 内部有三个重要的寄存器:计数寄存器(EPIT_CNR)、加载寄存器(EPIT_LR)和比较寄存器(EPIT_CMPR),这三个寄存器都是 32 位的。EPIT 是一个向下计数器,也就是说给它一个初值,它就会从这个给定的初值开始递减,直到减为 0,计数寄存器里面保存的就是当前的计数值。如果 EPIT 工作在 set-and-forget 模式下,当计数寄存器里面的值减少到 0, EPIT 就会重新从加载寄存器读取数值到计数寄存器里面,重新开始向下计数。比较寄存器里面保存的数值用于和计数寄存器里面的计数值比较,如果相等的话就会产生一个比较事件
  • ④、比较器。
  • ⑤、 EPIT 可以设置引脚输出,如果设置了的话就会通过指定的引脚输出信号。
  • ⑥、产生比较中断,也就是定时中断。

EPIT 定时器有两种工作模式:
set-and-forget 和 free-running,这两个工作模式的区别如下:

  • set-and-forget 模式(常用)
    EPITx_CR(x=1, 2)寄存器的 RLD 位置 1 的时候 EPIT 工作在此模式下,在此模式下 EPIT 的计数器从加载寄存器 EPITx_LR 中获取初始值,不能直接向计数器寄存器写入数据。不管什么时候,只要计数器计数到 0,那么就会从加载寄存器 EPITx_LR 中重新加载数据到计数器中,周而复始。
  • free-running 模式
    EPITx_CR 寄存器的 RLD 位清零的时候 EPIT 工作在此模式下,当计数器计数到0以后会重新从0XFFFFFFFF开始计数,并不是从加载寄存器EPITx_LR中获取数据。

接下来看一下 EPIT 重要的几个寄存器,第一个就是 EPIT 的配置寄存器 EPITx_CR,此寄存器的结构如下图所示:


寄存器 EPITx_CR 我们用到的重要位如下:

描述
CLKSRC(bit25:24)EPIT时钟源选择位,为 0 的时候关闭时钟源, 1 的时候选择选择Peripheral 时钟(ipg_clk),为 2 的时候选择 High-frequency 参考时钟(ipg_clk_highfreq),为 3 的时候选择 Low-frequency 参考时钟(ipg_clk_32k)。在本例程中,我们设置为 1,也就是选择 ipg_clk作为 EPIT 的时钟源, ipg_clk=66MHz。
PRESCALAR(bit15:4)EPIT 时钟源分频值,可设置范围 0~4095,分别对应 1~4096 分频。RLD(bit3): EPIT 工作模式,为 0 的时候工作在 free-running 模式,为 1 的时候工作在 setand-forget 模式。本章例程设置为 1,也就是工作在 set-and-forget 模式。OCIEN(bit2):比较中断使能位,为 0 的时候关闭比较中断,为 1 的时候使能比较中断,本章试验要使能比较中断。
ENMOD(bit1)设置计数器初始值,为 0 时计数器初始值等于上次关闭 EPIT 定时器以后计数器里面的值,为 1 的时候来源于加载寄存器。EN(bit0): EPIT 使能位,为 0 的时候关闭 EPIT,为 1 的时候使能 EPIT。

寄存器 EPITx_SR 结构体如下图 所示:

寄存器 EPITx_SR 只有一个位有效,那就是 OCIF(bit0),这个位是比较中断标志位,为 0 的时候表示没有比较事件发生,为 1 的时候表示有比较事件发生。当比较中断发生以后需要手动清除此位,此位是写 1 清零的。

寄存器 EPITx_LR、 EPITx_CMPR 和 EPITx_CNR 分别为加载寄存器、比较寄存器和计数寄存器,这三个寄存器都是用来存放数据的,很简单。

寄存器 EPITx_LR结构体如下图所示:

寄存器 EPITx_CMPR 结构体如下图 所示:

1.1、总结


通过上面的分析,EPIT 的配置步骤如下:

1、设置 EPIT1 的时钟源设置寄存器 EPIT1_CR 寄存器的 CLKSRC(bit25:24)位,选择 EPIT1 的时钟源。

2、设置分频值设置寄存器 EPIT1_CR 寄存器的 PRESCALAR(bit15:4)位,设置分频值。

3、设置工作模式设置寄存器 EPIT1_CR 的 RLD(bit3)位,设置 EPTI1 的工作模式。

4、设置计数器的初始值来源设置寄存器 EPIT1_CR 的 ENMOD(bit1)位, 设置计数器的初始值来源。

5、 使能比较中断我们要使用到比较中断,因此需要设置寄存器 EPIT1_CR 的 OCIEN(bit2)位,使能比较中断。

6、设置加载值和比较值设置寄存器 EPIT1_LR 中的加载值和寄存器 EPIT1_CMPR 中的比较值,通过这两个寄存器就可以决定定时器的中断周期。

7、 EPIT1 中断设置和中断服务函数编写使能 GIC 中对应的 EPIT1 中断,注册中断服务函数,如果需要的话还可以设置中断优先级。最后编写中断服务函数。

8、使能 EPIT1 定时器配置好 EPIT1 以后就可以使能 EPIT1 了,通过寄存器 EPIT1_CR 的 EN(bit0)位来设置。通过以上几步我们就配置好 EPIT 了,通过 EPIT 的比较中断来实现 LED0 的翻转。

2、按键消抖

为什么要用定时器来做按键消抖?

用到按键就要处理因为机械结构带来的按键抖动问题,也就是按键消抖。前面的实验中都是直接使用了延时函数来实现消抖,因为简单,但是直接用延时函数来实现消抖会浪费 CPU 性能,因为在延时函数里面 CPU 什么都做不了。如果按键使用中断的话更不能在中断里面使用延时函数,因为中断服务函数要快进快出!本次我们学习如何使用定时器来实现按键消抖,使用定时器既可以实现按键消抖,而且也不会浪费CPU 性能,这个也是 Linux 驱动里面按键消抖的做法

定时器按键消抖原理

按键消抖的原理其实就是在按键按下以后延时一段时间再去读取按键值,如果此时按键值还有效那就表示这是一次有效的按键,中间的延时就是消抖的。但是这有一个缺点,就是延时函数会浪费 CPU 性能,因为延时函数就是空跑。如果按键是用中断方式实现的,那就更不能在中断服务函数里面使用延时函数,因为中断服务函数最基本的要求就是快进快出!

上一篇博文我们学习了 EPIT 定时器,定时器设置好定时时间,然后 CPU 就可以做其他事情去了,定时时间到了以后就会触发中断,然后在中断中做相应的处理即可。因此,我们可以借助定时器来实现消抖,按键采用中断驱动方式,当按键按下以后触发按键中断,在按键中断中开启一个定时器,定时周期为 10ms,当定时时间到了以后就会触发定时器中断,最后在定时器中断处理函数中读取按键的值,如果按键值还是按下状态那就表示这是一次有效的按键。定时器按键消抖如下图所示:

在图 19.1.1 中 t1~t3 这一段时间就是按键抖动,是需要消除的。设置按键为下降沿触发,因此会在 t1、 t2 和 t3 这三个时刻会触发按键中断,每次进入中断处理函数都会重新开器定时器中断,所以会在 t1、 t2 和 t3 这三个时刻开器定时器中断。但是 t1~t2 和 t2~t3 这两个时间段是小于我们设置的定时器中断周期(也就是消抖时间,比如 10ms),所以虽然 t1 开启了定时器,但是定时器定时时间还没到呢 ,t2 时刻就重置了定时器,最终只有 t3 时刻开启的定时器能完整的完成整个定时周期并触发中断,我们就可以在中断处理函数里面做按键处理了,这就是定时器实现按键防抖的原理, Linux 里面的按键驱动用的就是这个原理!

以上是关于ARM(I.MX6ULL) EPIT定时器详解定时器按键消抖的主要内容,如果未能解决你的问题,请参考以下文章

EPIT定时器实验

NXP (I.MX6ULL) GPT高精度延时定时器

ARM(IMX6U)裸机之I.MX6ULL启动方式详解

i.MX6ULL驱动开发 | 19 - Linux内核定时器的编程方法与使用示例

i.MX6ULL驱动开发 | 19 - Linux内核定时器的编程方法与使用示例

ARM(IMX6U)裸机之I.MX6ULL启动头文件的详解