【裸机开发】EPIT 定时器 —— 按键消抖

实际工程中,不能直接通过延时来消抖 ! 这里我们采用定时器来消抖,这也是内核处理消抖的一种方式。


目录

一、基本原理

1、延时消抖的弊端

2、定时器消抖原理

二、按键消抖实现

1、按键中断

2、定时器中断

三、附加:按键 / 定时器中断初始化 

1、按键初始化

2、定时器初始化


一、基本原理

1、延时消抖的弊端

按键按下的时候,存在抖动,延时消抖其实就是不管中间抖了多少下,全都忽略。这样的话,不确定因素太多。

  • 延时设置的过短可能无法达到消抖的效果;
  • 延时设置的过长可能会存在“第一次按键按下没反应,第二次才有反应”的情况。这就是延时过长导致第一次按下被无视。

2、定时器消抖原理

定时器消抖则是考虑了每一次的抖动。当 t1 时刻产生一次抖动时,我们启动一个定时器,定时器的周期为 10 ms(10ms已经基本覆盖了全部的抖动)

第二次检测到抖动的时候,此时按理说还没有触发中断,我们再次启动定时器,第一次和第二次用的同一个定时器,所以这次定时器启动时会重新计数。

如此往复,直到最后一次抖动出现之前,定时器在不断被刷新计数,始终没有触发过中断,即没有调用过中断服务函数。

当最后一次抖动出现时,说明抖动过程已经结束,此时会调用中断服务函数,中断服务函数里要做的就是按键按下以后的处理逻辑。

这里涉及到两个中断,分别是按键中断、定时器中断

  • 按键中断:中断触发时,启动定时器
  • 定时器中断:中断触发时,执行按键按下以后的处理逻辑

二、按键消抖实现

定时器实现按键消抖的关键在于设置两个中断服务函数。

1、按键中断

每次按键中断触发的时候(假设是下降沿触发),我们都要重新启动 EPIT1 定时器,此时定时器就会刷新计数,重新开始计时。

void key_irqhandler(void* userParams)
{
    restart_epit(33000000/100);     // 启动定时器(每隔10ms触发一次中断)
    GPIO1_ISR |= (1 << 18);
}

restart_epit 函数在最后的《定时器中断初始化》部分。在使用 restart_epit 之前,需要在 main.c 中先调用 epit_init 函数初始化定时器。

2、定时器中断

按键抖动的时候,不会触发定时器中断,只有当按键出现最后一次抖动时(按键抖动过程结束),才会触发定时器中断,此时再实现我们原本希望按键按下时该做的事。

假设我们希望按键按下时,切换LED灯的状态。

void epit_irqhandler(void* userParams)
{
    stop_epit();        // 防止处理中断时,按键再次被按下,影响现有的中断处理
    if (((GPIO1_DR >> 18) & 0x01) == 0)
    {
        switch_led(epit_stat);
        epit_stat = !epit_stat;
    }
    
    EPIT1_SR |= 1;           // 清除中断标志位
}

三、附加:按键 / 定时器中断初始化 

使用中断之前,必然需要先进行中断初始化,这里附上按键和定时器的初始化操作。

1、按键初始化

/* 按键初始化 */
void key_init()
{
    /* 1、设置IO复用为GPIO1_IO03 */
    IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B = 0x5;

    /* 2、初始化复用引脚,设置电气属性 */
    IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B = 0xF080;

    /* 3、初始化GPIO1 */
    GPIO1_GDIR &= ~(1 << 18);

    /* 4、按键中断初始化 */
    key_int_init();
}

/* 按键中断初始化 */
void key_int_init()
{
    /* 使能GIC 中 IRQ 的某个外设对应的中断 */
    GIC_EnableIRQ(99);    // 99 表示 GPIO1_IO16 ~ 31 的中断

    // GPIO1 中断使能
    GPIO1_IMR |= (1 << 18);

    // 配置 GPIO1_IO18 中断触发方式(下降沿触发)
    GPIO1_EDGE_SEL &= ~(1 << 18);
    GPIO1_ICR2 |= (3 << 4);

    // 注册中断服务函数
    register_irqhandler(99, key_irqhandler);
}

2、定时器初始化

定时器初始化时,暂时先不打开定时器,因为要触发了按键中断以后再启动定时器。

/*
 * frac: 代表分频数
 * interval: 代表计数器的初始值
 */
void epit_init(unsigned int frac, unsigned int value)
{
    if (frac < 1 )
        frac = 1;
    else if(frac > 4096)
        frac = 4096;
    
    EPIT1_CR = 0;       // CR 寄存器清零(停止定时器)
    /* EPIT1 使能、分频、时钟源初始化 */
    EPIT1_CR |=(0xE | ((frac - 1) << 4) | (0x1 << 24));

    /* 加载寄存器 */
    EPIT1_LR = value;

    /* 比较寄存器 */
    EPIT1_CMPR = 0;

    /* EPIT1 中断使能 */
    GIC_EnableIRQ(88);

    /* 注册中断服务函数 */
    register_irqhandler(88, epit_irqhandler);

    /* 计数寄存器 */
    // EPIT1_CNR = value;

    // EPIT1_CR |= 1;          // 启动定时器
}

/*
 * 停止定时器
 */
void stop_epit()
{
    EPIT1_CR &= ~(1 << 0);
}

/*
 * 启动定时器
 */ 
void restart_epit(unsigned int val)
{
    stop_epit();
    EPIT1_LR = val;
    EPIT1_CR |= 1;          // 启动定时器
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: i.MX6 EPIT(Enhanced Periodic Interrupt Timer)是一种双向计时器,可用于实现嵌入式Linux中的计时器功能,如周期性中断、定期任务等。 i.MX6 EPIT定时器驱动是在Linux内核中实现EPIT的驱动程序,可通过/sys/class/timer/epit目录下的文件进行控制。该驱动程序使用了内核中的定时器子系统,支持定时器的配置、开启、关闭和重启功能。 EPIT定时器具有多种模式,可实现周期性中断、单次计时、连续计时等。驱动程序提供了获取当前定时器计数器和比较器值、设置比较器值、配置定时器模式和时钟源等接口。 在应用程序中,可以利用EPIT定时器驱动实现心跳包发送、数据采集、定时任务等功能。例如,定期采集传感器数据可以使用连续计时模式,每隔一段时间触发一次中断,读取传感器数据并进行处理,以便实现对数据的实时监测和分析。 总之,i.MX6 EPIT定时器驱动在嵌入式Linux系统中具有广泛的应用场景,是实现计时器功能的重要组成部分。 ### 回答2: i.mx6 epit定时器驱动是一种用于控制时间计数和时序操作的驱动程序。i.mx6 epit定时器驱动是针对ARM架构的一种硬件计时器,其可在一定时间范围内对计时周期进行划分,并且在计时到达特定时间节点时可以触发相应的中断信号。这种特性有助于对系统中各个模块的时间操控和协同进行更加精确和高效的管理。 在实现i.mx6 epit定时器驱动时,需要首先对硬件的时钟和计数器进行初始化,同时规划好所需要的计时周期及其对应的中断服务程序。其次,需要根据实际应用场景,选择合适的工作模式,比如定时器的循环工作模式和单次工作模式等。此外,i.mx6 epit定时器驱动还可通过设置各种定时器的触发条件、分频系数、计数器值、预定中断周期等参数来指导其工作。 i.mx6 epit定时器驱动在实际应用中,可以用于很多领域比如:测量仪、定时器、中断控制、数据采集、总线同步、状态监测等。同时,在多任务操作系统中,也可以将i.mx6 epit定时器驱动与系统时钟的管理器进行集成,以实现更加高效和稳定的系统时间管理。 综上所述,i.mx6 epit定时器驱动是一种用于时间计数和时序操作的驱动程序,具有精确高效的特点,并且在多领域应用中有着广泛的应用价值。 ### 回答3: i.MX6 EPIT (Enhanced Periodic Interval Timer)是一种高级计时器,用于基于ARM Cortex-A9的i.MX6处理器。它具有精确的定时器功能和多种配置选项,可用于实现高精度周期性操作,如定时中断、PWM (脉宽调制)等。在嵌入式系统中,i.MX6 EPIT常用于实现精确定时、控制外设、任务切换等功能。 驱动i.MX6 EPIT定时器需要在内核中实现一个设备驱动程序。该驱动程序需要完成以下几个主要任务: 1. 初始化EPIT定时器,包括设置时钟源、预分频、计数模式、计时周期等。 2. 响应定时器中断,即在定时器达到预定的时间时触发中断。在中断处理程序中,可以执行相应的操作,如更新任务状态、控制外设、发送信号等。 3. 提供用户接口,允许应用程序通过ioctl系统调用配置和控制定时器。例如,可以通过ioctl命令来设置定时周期、使能定时器、暂停定时器等。 在实现EPIT定时器驱动时,需要注意以下几个关键点: 1. 时钟源选择。i.MX6处理器内部有多个时钟源可供选择,如ARM内核时钟、PLL时钟、外部时钟输入等。需要根据应用场景选择适合的时钟源,并进行相应的配置。 2. 计时精度。EPIT定时器的计时精度可以通过预分频系数和计数位宽来控制。需要根据具体需求进行合理的配置,以实现满足精度要求的定时功能。 3. 中断处理。在中断处理程序中,需要注意避免阻塞和死锁问题,防止同时发生多个中断导致系统崩溃。 4. 设备节点的创建和管理。通过设备节点,驱动程序可以与用户空间的应用程序进行交互。需要正确创建和管理设备节点,保证应用程序与驱动之间的通信正常进行。 总之,实现i.MX6 EPIT定时器驱动需要对硬件及其编程接口有一定的了解,同时结合系统需求进行合理的配置和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值