【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

这篇具有很好参考价值的文章主要介绍了【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、EPIT 定时器简介

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

EPIT 是一个 32 位定时器,在处理器几乎不用介入的情况下提供精准的定时中断,软件使能以后 EPIT 就会开始运行, EPIT 定时器有如下特点:
  ①:时钟源可选的 32 位向下计数器。
  ②:12 位的分频值。
  ③:当计数值和比较值相等的时候产生中断。

EPIT 定时器结构如图所示:
【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖
图中各部分的功能如下:
  ①:这是个多路选择器,用来选择 EPIT 定时器的时钟源, EPIT 共有 3 个时钟源可选择,ipg_clk、 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,此寄存器的结构如图所示:
【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖
【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

寄存器 EPITx_SR 结构体如图所示:
【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

EPIT 的配置步骤如下:

【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

程序编写文章来源地址https://www.toymoban.com/news/detail-431833.html

#ifndef _BSP_EXIT_H
#define _BSP_EXIT_H
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_exit.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : 外部中断驱动头文件。
其他	   : 配置按键对应的GPIP为中断模式
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/
#include "imx6ul.h"

/* 函数声明 */
void exit_init(void);						/* 中断初始化 */
void gpio1_io18_irqhandler(void); 			/* 中断处理函数 */

#endif
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_exit.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : 外部中断驱动。
其他	   : 配置按键对应的GPIP为中断模式
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/
#include "bsp_exit.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_delay.h"
#include "bsp_beep.h"

/*
 * @description			: 初始化外部中断
 * @param				: 无
 * @return 				: 无
 */
void exit_init(void)
{
	gpio_pin_config_t key_config;

	/* 1、设置IO复用 */
	IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);			/* 复用为GPIO1_IO18 */
	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);

	GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);				/* 使能GIC中对应的中断 */
	system_register_irqhandler(GPIO1_Combined_16_31_IRQn, (system_irq_handler_t)gpio1_io18_irqhandler, NULL);	/* 注册中断服务函数 */
	gpio_enableint(GPIO1, 18);								/* 使能GPIO1_IO18的中断功能 */
}

/*
 * @description			: GPIO1_IO18最终的中断处理函数
 * @param				: 无
 * @return 				: 无
 */
void gpio1_io18_irqhandler(void)
{ 
	static unsigned char state = 0;

	/*
	 *采用延时消抖,中断服务函数中禁止使用延时函数!因为中断服务需要
	 *快进快出!!这里为了演示所以采用了延时函数进行消抖,后面我们会讲解
	 *定时器中断消抖法!!!
 	 */

	delay(10);
	if(gpio_pinread(GPIO1, 18) == 0)	/* 按键按下了  */
	{
		state = !state;
		beep_switch(state);
	}
	
	gpio_clearintflags(GPIO1, 18); /* 清除中断标志位 */
}

二、定时器按键消抖

按键消抖的原理就是在按键按下以后延时一段时间再去读取按键值,如果此时按键值还有效那就表示这是一次有效的按键,中间的延时就是消抖的。但是这有一个缺点,就是延时函数会浪费 CPU 性能,因为延时函数就是空跑。如果按键是用中断方式实现的,那就更不能在中断服务函数里面使用延时函数,因为中断服务函数最基本的要求就是快进快出!上一章我们学习了 EPIT 定时器,定时器设置好定时时间,然后 CPU 就可以做其他事情去了,定时时间到了以后就会触发中断,然后在中断中做相应的处理即可。因此,我们可以借助定时器来实现消抖,按键采用中断驱动方式,当按键按下以后触发按键中断,在按键中断中开启一个定时器,定时周期为 10ms,当定时时间到了以后就会触发定时器中断,最后在定时器中断处理函数中读取按键的值,如果按键值还是按下状态那就表示这是一次有效的按键。定时器按键消抖如图所示:

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


关于定时器按键消抖的原理就介绍到这里,接下来讲解如何使用 EPIT1 来配合按键 KEY来实现具体的消抖,步骤如下:
【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

程序编写

#ifndef _BSP_KEYFILTER_H
#define _BSP_KEYFILTER_H
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_keyfilter.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : 定时器按键消抖驱动头文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/5 左忠凯创建
***************************************************************/


/* 函数声明 */
void filterkey_init(void);
void filtertimer_init(unsigned int value);
void filtertimer_stop(void);
void filtertimer_restart(unsigned int value);
void filtertimer_irqhandler(void);
void gpio1_16_31_irqhandler(void);

#endif
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_keyfilter.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : 定时器按键消抖驱动。
其他	   : 按键采用中断方式,按下按键触发按键中断,在按键中断里面
  		 使能定时器定时中断。使用定时器定时中断来完成消抖延时,
  		 定时器中断周期就是延时时间。如果定时器定时中断触发,
  		 表示消抖完成(延时周期完成),即可执行按键处理函数。
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/5 左忠凯创建
***************************************************************/
#include "bsp_key.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_beep.h"
#include "bsp_keyfilter.h"

/*
 * @description		: 按键初始化
 * @param			: 无
 * @return 			: 无
 */
void filterkey_init(void)
{	
	gpio_pin_config_t key_config;
	
	/* 1、初始化IO复用 */
	IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);	/* 复用为GPIO1_IO18 */

	/* 2、、配置GPIO1_IO18的IO属性	
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 11 默认22K上拉
	 *bit [13]: 1 pull功能
	 *bit [12]: 1 pull/keeper使能
	 *bit [11]: 0 关闭开路输出
	 *bit [7:6]: 10 速度100Mhz
	 *bit [5:3]: 000 关闭输出
	 *bit [0]: 0 低转换率
	 */
	IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);
	
	/* 3、初始化GPIO为中断 */
	key_config.direction = kGPIO_DigitalInput;
	key_config.interruptMode = kGPIO_IntFallingEdge;
	key_config.outputLogic = 1;
	gpio_init(GPIO1, 18, &key_config);

	GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn); /* 使能GIC中对应的中断   		  */
	
	/* 注册中断服务函数 */
	system_register_irqhandler(GPIO1_Combined_16_31_IRQn, 
							   (system_irq_handler_t)gpio1_16_31_irqhandler, 
							   NULL);
	
	gpio_enableint(GPIO1, 18);		/* 使能GPIO1_IO18的中断功能 */

	filtertimer_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);	
}

/*
 * @description		: 关闭定时器
 * @param 			: 无
 * @return 			: 无
 */
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);	/* 打开定时器 		*/
}

/*
 * @description		: 定时器中断处理函数 
 * @param			: 无
 * @return 			: 无
 */
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; 						/* 清除中断标志位 				*/
}

/*
 * @description		: GPIO中断处理函数
 * @param			: 无
 * @return 			: 无
 */
void gpio1_16_31_irqhandler(void)
{ 
	/* 开启定时器 */
	filtertimer_restart(66000000/100);

	/* 清除中断标志位 */
	gpio_clearintflags(GPIO1, 18);
}

到了这里,关于【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • I.MX6U C语言运行环境构建及驱动开发格式

    1.设置处理器模式 设置6ULL处于SVC模式下。设置下CPSR寄存器的bit4-0,也就是M[4:0]为10011=0x13.。读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器里面,MSR指令将通用寄存器的值写入到CPSR寄存器里面去。 2.设置SP指针 SP可以指向内部RAM,也可以指向DDR,我

    2024年02月19日
    浏览(37)
  • I.MX6ull GPT高精度定时器

    一 简介 GPT的全称是General Purpose Timer,它是一个32位的向上的定时器, GPT 定时器也可以跟一个值进行比较,当计数器值和这个值相等的话就发生比较事件,产生比较中断。GPT 定时器有一个 12 位的分频器,可以对 GPT 定时器的时钟源进行分频。 分析方式 同EPTI  它具有以下特点

    2024年02月08日
    浏览(54)
  • 看完这篇文章你就彻底懂啦{保姆级讲解}-----(I.MX6U驱动UART串口通信) 2023.5.20

    串口是我们在开发过程中最常用到的外设,所以我们必须掌握。 串口驱动初始化部分 好!按照老样子,接下来开始详细讲解每行代码的用处,以及为什么这样写! 串口驱动初始化部分讲解开始: //将IO功能设置为UART1_RXD和UART1_TXD。 //配置UART1_TX_DATA、UART1_RX_DATA的IO属性。 先关

    2024年02月05日
    浏览(108)
  • EPIT定时器实验(一)

    EPIT:Enhanced Periodic Interrupt Timer,直译就是增强的周期中断定时器,它主要完成周期性中断定时的。 STM32里面的定时器有很多其它功能,比如输入捕获、PWM输出等,但是I.MX6U的的EPIT定时器只是完成周期性中断定时的,仅此一项功能。至于输入捕获、PWM 输出等这些功能,I.MX6U

    2024年02月01日
    浏览(35)
  • linuxARM裸机学习笔记(4)----GPIO中断以及定时器中断实验

    这个表里面存放的都是中断向量,中断服务程序的入口地址或存放中断服务程序的首地址成为中断向量。中断向量表是一系列中断服务程序入口地址组成的表,当某个中断触发的时候会自动跳转到中断向量表对应的中断服务程序的入口。 2.NVIC(内嵌向量中断控制器) 在IMU6U的中

    2024年02月14日
    浏览(45)
  • PWM定时器精准定时实现led闪烁(S3C2440裸机开发)

    上期和大家分享了使用PWM定时器输出周期方波驱动蜂鸣器,那么本期分享的内容是使用PWM定时器实现定时器的功能,有了上期的基础,这期分享的内容大家理解起来应该非常easy,接下来看一下吧! PWM定时器的原理其实是使用了中断,这里使用的定时器0; 如下实现的是每过两

    2024年02月15日
    浏览(47)
  • 【裸机开发】GPT 定时器(一) —— GPT的功能、寄存器解析

    后续需要使用 GPT 计数器实现中断以及延时,这里我们需要先了解一下GPT的功能以及相关寄存器。 目录 一、GPT 定时器的功能 1、计数器 2、输入捕获 3、输出比较(GPT的两种工作模式) 二、寄存器解析 1、GPTx_CR 2、GPTx_PR 3、GPTx_SR 4、GPTx_IR 5、GPTx_OCRn 6、GPTx_ICRn 7、GPTx_CNT gpt 定时

    2024年02月12日
    浏览(52)
  • 【Linux 裸机篇(五)】I.MX6ULL BSP工程管理下的 Makefile编写、链接脚本

    文件夹 描述 bsp 存放驱动文件 imx6ul 存放跟芯片有关的文件,比如 NXP 官方的 SDK库文件 obj 存放编译生成的.o 文件 project 存放 start.S 和 main.c 文件,也就是应用文件 行 描述 1~7 定义了一些变量,除了第 2 行以外其它的都是跟编译器有关的,如果使用其它编译器的话只需要修改第

    2023年04月20日
    浏览(48)
  • linuxARM裸机学习笔记(5)----定时器按键消抖和高精度延时实验

    之前的延时消抖,是直接借助delay函数进行的,但是这样会浪费CPU的性能。我们采用延时函数的方式实现,可以实现快进快出。  定时器消抖,必须是在t3的时间点才可以,当在t1,t2的时间点每次进入中断函数都要重新开启定时器的计时 但是,这两个时间点的时间小于定时器设

    2024年02月14日
    浏览(73)
  • Linux定时器

    Linux定时器是一种 软件机制 ,用于在指定的时间间隔或特定时间点执行特定的任务。它是 基于内核的机制 ,可以用于各种应用场景,如定时任务调度、延时处理、周期性事件触发等。 运作机制(工作原理):Linux定时器的工作原理主要分为两个部分:定时器的创建和定时器

    2024年02月03日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包