一、EPIT 定時(shí)器簡介
EPIT 的全稱是: Enhanced Periodic Interrupt Timer,直譯過來就是增強(qiáng)的周期中斷定時(shí)器,它主要是完成周期性中斷定時(shí)的。學(xué)過 STM32 的話應(yīng)該知道, STM32 里面的定時(shí)器還有很多其它的功能,比如輸入捕獲、 PWM 輸出等等。但是 I.MX6U 的 EPIT 定時(shí)器只是完成周期性中斷定時(shí)的,僅此一項(xiàng)功能!至于輸入捕獲、 PWM 輸出等這些功能, I.MX6U由其它的外設(shè)來完成。
EPIT 是一個(gè) 32 位定時(shí)器,在處理器幾乎不用介入的情況下提供精準(zhǔn)的定時(shí)中斷,軟件使能以后 EPIT 就會(huì)開始運(yùn)行, EPIT 定時(shí)器有如下特點(diǎn):
??①:時(shí)鐘源可選的 32 位向下計(jì)數(shù)器。
??②:12 位的分頻值。
??③:當(dāng)計(jì)數(shù)值和比較值相等的時(shí)候產(chǎn)生中斷。
EPIT 定時(shí)器結(jié)構(gòu)如圖所示:
圖中各部分的功能如下:
??①:這是個(gè)多路選擇器,用來選擇 EPIT 定時(shí)器的時(shí)鐘源, EPIT 共有 3 個(gè)時(shí)鐘源可選擇,ipg_clk、 ipg_clk_32k 和 ipg_clk_highfreq。
??②:這是一個(gè) 12 位的分頻器,負(fù)責(zé)對(duì)時(shí)鐘源進(jìn)行分頻, 12 位對(duì)應(yīng)的值是 0~4095,對(duì)應(yīng)著 1~4096 分頻。
??③:經(jīng)過分頻的時(shí)鐘進(jìn)入到 EPIT 內(nèi)部,在 EPIT 內(nèi)部有三個(gè)重要的寄存器:計(jì)數(shù)寄存器(EPIT_CNR)、加載寄存器(EPIT_LR)和比較寄存器(EPIT_CMPR),這三個(gè)寄存器都是 32 位的。EPIT 是一個(gè)向下計(jì)數(shù)器,也就是說給它一個(gè)初值,它就會(huì)從這個(gè)給定的初值開始遞減,直到減為 0,計(jì)數(shù)寄存器里面保存的就是當(dāng)前的計(jì)數(shù)值。如果 EPIT 工作在 set-and-forget 模式下,當(dāng)計(jì)數(shù)寄存器里面的值減少到 0, EPIT 就會(huì)重新從加載寄存器讀取數(shù)值到計(jì)數(shù)寄存器里面,重新開始向下計(jì)數(shù)。比較寄存器里面保存的數(shù)值用于和計(jì)數(shù)寄存器里面的計(jì)數(shù)值比較,如果相等的話就會(huì)產(chǎn)生一個(gè)比較事件。
??④:比較器。
??⑤:EPIT 可以設(shè)置引腳輸出,如果設(shè)置了的話就會(huì)通過指定的引腳輸出信號(hào)。
??⑥:產(chǎn)生比較中斷,也就是定時(shí)中斷。
EPIT 定時(shí)器有兩種工作模式: set-and-forget 和 free-running,這兩個(gè)工作模式的區(qū)別如下:
??set-and-forget 模式:EPITx_CR(x=1, 2)寄存器的 RLD 位置 1 的時(shí)候 EPIT 工作在此模式下,在此模式下 EPIT 的計(jì)數(shù)器從加載寄存器 EPITx_LR 中獲取初始值,不能直接向計(jì)數(shù)器寄存器寫入數(shù)據(jù)。不管什么時(shí)候,只要計(jì)數(shù)器計(jì)數(shù)到 0,那么就會(huì)從加載寄存器 EPITx_LR 中重新加載數(shù)據(jù)到計(jì)數(shù)器中,周而復(fù)始。
??free-running 模式: EPITx_CR 寄存器的 RLD 位清零的時(shí)候 EPIT 工作在此模式下,當(dāng)計(jì)數(shù)器計(jì)數(shù)到0以后會(huì)重新從0XFFFFFFFF開始計(jì)數(shù),并不是從加載寄存器 EPITx_LR中獲取數(shù)據(jù)。
接下來看一下 EPIT 重要的幾個(gè)寄存器,第一個(gè)就是 EPIT 的配置寄存器 EPITx_CR,此寄存器的結(jié)構(gòu)如圖所示:
寄存器 EPITx_SR 結(jié)構(gòu)體如圖所示:
EPIT 的配置步驟如下:
程序編寫文章來源地址http://www.zghlxwxcb.cn/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
描述 : 外部中斷驅(qū)動(dòng)頭文件。
其他 : 配置按鍵對(duì)應(yīng)的GPIP為中斷模式
論壇 : www.wtmembed.com
日志 : 初版V1.0 2019/1/4 左忠凱創(chuàng)建
***************************************************************/
#include "imx6ul.h"
/* 函數(shù)聲明 */
void exit_init(void); /* 中斷初始化 */
void gpio1_io18_irqhandler(void); /* 中斷處理函數(shù) */
#endif
/***************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_exit.c
作者 : 左忠凱
版本 : V1.0
描述 : 外部中斷驅(qū)動(dòng)。
其他 : 配置按鍵對(duì)應(yīng)的GPIP為中斷模式
論壇 : www.wtmembed.com
日志 : 初版V1.0 2019/1/4 左忠凱創(chuàng)建
***************************************************************/
#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、設(shè)置IO復(fù)用 */
IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0); /* 復(fù)用為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中對(duì)應(yīng)的中斷 */
system_register_irqhandler(GPIO1_Combined_16_31_IRQn, (system_irq_handler_t)gpio1_io18_irqhandler, NULL); /* 注冊(cè)中斷服務(wù)函數(shù) */
gpio_enableint(GPIO1, 18); /* 使能GPIO1_IO18的中斷功能 */
}
/*
* @description : GPIO1_IO18最終的中斷處理函數(shù)
* @param : 無
* @return : 無
*/
void gpio1_io18_irqhandler(void)
{
static unsigned char state = 0;
/*
*采用延時(shí)消抖,中斷服務(wù)函數(shù)中禁止使用延時(shí)函數(shù)!因?yàn)橹袛喾?wù)需要
*快進(jìn)快出!!這里為了演示所以采用了延時(shí)函數(shù)進(jìn)行消抖,后面我們會(huì)講解
*定時(shí)器中斷消抖法?。?!
*/
delay(10);
if(gpio_pinread(GPIO1, 18) == 0) /* 按鍵按下了 */
{
state = !state;
beep_switch(state);
}
gpio_clearintflags(GPIO1, 18); /* 清除中斷標(biāo)志位 */
}
二、定時(shí)器按鍵消抖
按鍵消抖的原理就是在按鍵按下以后延時(shí)一段時(shí)間再去讀取按鍵值,如果此時(shí)按鍵值還有效那就表示這是一次有效的按鍵,中間的延時(shí)就是消抖的。但是這有一個(gè)缺點(diǎn),就是延時(shí)函數(shù)會(huì)浪費(fèi) CPU 性能,因?yàn)檠訒r(shí)函數(shù)就是空跑。如果按鍵是用中斷方式實(shí)現(xiàn)的,那就更不能在中斷服務(wù)函數(shù)里面使用延時(shí)函數(shù),因?yàn)橹袛喾?wù)函數(shù)最基本的要求就是快進(jìn)快出!上一章我們學(xué)習(xí)了 EPIT 定時(shí)器,定時(shí)器設(shè)置好定時(shí)時(shí)間,然后 CPU 就可以做其他事情去了,定時(shí)時(shí)間到了以后就會(huì)觸發(fā)中斷,然后在中斷中做相應(yīng)的處理即可。因此,我們可以借助定時(shí)器來實(shí)現(xiàn)消抖,按鍵采用中斷驅(qū)動(dòng)方式,當(dāng)按鍵按下以后觸發(fā)按鍵中斷,在按鍵中斷中開啟一個(gè)定時(shí)器,定時(shí)周期為 10ms,當(dāng)定時(shí)時(shí)間到了以后就會(huì)觸發(fā)定時(shí)器中斷,最后在定時(shí)器中斷處理函數(shù)中讀取按鍵的值,如果按鍵值還是按下狀態(tài)那就表示這是一次有效的按鍵。定時(shí)器按鍵消抖如圖所示:
圖中 t1~t3 這一段時(shí)間就是按鍵抖動(dòng),是需要消除的。設(shè)置按鍵為下降沿觸發(fā),因此會(huì)在 t1、 t2 和 t3 這三個(gè)時(shí)刻會(huì)觸發(fā)按鍵中斷,每次進(jìn)入中斷處理函數(shù)都會(huì)重新開器定時(shí)器中斷,所以會(huì)在 t1、 t2 和 t3 這三個(gè)時(shí)刻開器定時(shí)器中斷。但是 t1~t2 和 t2~t3 這兩個(gè)時(shí)間段是小于我們?cè)O(shè)置的定時(shí)器中斷周期(也就是消抖時(shí)間,比如 10ms),所以雖然 t1 開啟了定時(shí)器,但是定時(shí)器定時(shí)時(shí)間還沒到呢 t2 時(shí)刻就重置了定時(shí)器,最終只有 t3 時(shí)刻開啟的定時(shí)器能完整的完成整個(gè)定時(shí)周期并觸發(fā)中斷,我們就可以在中斷處理函數(shù)里面做按鍵處理了,這就是定時(shí)器實(shí)現(xiàn)按鍵防抖的原理, Linux 里面的按鍵驅(qū)動(dòng)用的就是這個(gè)原理!
關(guān)于定時(shí)器按鍵消抖的原理就介紹到這里,接下來講解如何使用 EPIT1 來配合按鍵 KEY來實(shí)現(xiàn)具體的消抖,步驟如下:
文章來源:http://www.zghlxwxcb.cn/news/detail-431833.html
程序編寫
#ifndef _BSP_KEYFILTER_H
#define _BSP_KEYFILTER_H
/***************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_keyfilter.h
作者 : 左忠凱
版本 : V1.0
描述 : 定時(shí)器按鍵消抖驅(qū)動(dòng)頭文件。
其他 : 無
論壇 : www.wtmembed.com
日志 : 初版V1.0 2019/1/5 左忠凱創(chuàng)建
***************************************************************/
/* 函數(shù)聲明 */
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
描述 : 定時(shí)器按鍵消抖驅(qū)動(dòng)。
其他 : 按鍵采用中斷方式,按下按鍵觸發(fā)按鍵中斷,在按鍵中斷里面
使能定時(shí)器定時(shí)中斷。使用定時(shí)器定時(shí)中斷來完成消抖延時(shí),
定時(shí)器中斷周期就是延時(shí)時(shí)間。如果定時(shí)器定時(shí)中斷觸發(fā),
表示消抖完成(延時(shí)周期完成),即可執(zhí)行按鍵處理函數(shù)。
論壇 : www.wtmembed.com
日志 : 初版V1.0 2019/1/5 左忠凱創(chuàng)建
***************************************************************/
#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復(fù)用 */
IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0); /* 復(fù)用為GPIO1_IO18 */
/* 2、、配置GPIO1_IO18的IO屬性
*bit 16:0 HYS關(guān)閉
*bit [15:14]: 11 默認(rèn)22K上拉
*bit [13]: 1 pull功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 關(guān)閉開路輸出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 000 關(guān)閉輸出
*bit [0]: 0 低轉(zhuǎn)換率
*/
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中對(duì)應(yīng)的中斷 */
/* 注冊(cè)中斷服務(wù)函數(shù) */
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); /* 初始化定時(shí)器,10ms */
}
/*
* @description : 初始化用于消抖的定時(shí)器,默認(rèn)關(guān)閉定時(shí)器
* @param - value : 定時(shí)器EPIT計(jì)數(shù)值
* @return : 無
*/
void filtertimer_init(unsigned int value)
{
EPIT1->CR = 0; //先清零
/*
* CR寄存器:
* bit25:24 01 時(shí)鐘源選擇Peripheral clock=66MHz
* bit15:4 0 1分頻
* bit3: 1 當(dāng)計(jì)數(shù)器到0的話從LR重新加載數(shù)值
* bit2: 1 比較中斷使能
* bit1: 1 初始計(jì)數(shù)值來源于LR寄存器值
* bit0: 0 先關(guān)閉EPIT1
*/
EPIT1->CR = (1<<24 | 1<<3 | 1<<2 | 1<<1);
/* 計(jì)數(shù)值 */
EPIT1->LR = value;
/* 比較寄存器,當(dāng)計(jì)數(shù)器值和此寄存器值相等的話就會(huì)產(chǎn)生中斷 */
EPIT1->CMPR = 0;
GIC_EnableIRQ(EPIT1_IRQn); /* 使能GIC中對(duì)應(yīng)的中斷 */
/* 注冊(cè)中斷服務(wù)函數(shù) */
system_register_irqhandler(EPIT1_IRQn, (system_irq_handler_t)filtertimer_irqhandler, NULL);
}
/*
* @description : 關(guān)閉定時(shí)器
* @param : 無
* @return : 無
*/
void filtertimer_stop(void)
{
EPIT1->CR &= ~(1<<0); /* 關(guān)閉定時(shí)器 */
}
/*
* @description : 重啟定時(shí)器
* @param - value : 定時(shí)器EPIT計(jì)數(shù)值
* @return : 無
*/
void filtertimer_restart(unsigned int value)
{
EPIT1->CR &= ~(1<<0); /* 先關(guān)閉定時(shí)器 */
EPIT1->LR = value; /* 計(jì)數(shù)值 */
EPIT1->CR |= (1<<0); /* 打開定時(shí)器 */
}
/*
* @description : 定時(shí)器中斷處理函數(shù)
* @param : 無
* @return : 無
*/
void filtertimer_irqhandler(void)
{
static unsigned char state = OFF;
if(EPIT1->SR & (1<<0)) /* 判斷比較事件是否發(fā)生 */
{
filtertimer_stop(); /* 關(guān)閉定時(shí)器 */
if(gpio_pinread(GPIO1, 18) == 0) /* KEY0 */
{
state = !state;
beep_switch(state); /* 反轉(zhuǎn)蜂鳴器 */
}
}
EPIT1->SR |= 1<<0; /* 清除中斷標(biāo)志位 */
}
/*
* @description : GPIO中斷處理函數(shù)
* @param : 無
* @return : 無
*/
void gpio1_16_31_irqhandler(void)
{
/* 開啟定時(shí)器 */
filtertimer_restart(66000000/100);
/* 清除中斷標(biāo)志位 */
gpio_clearintflags(GPIO1, 18);
}
到了這里,關(guān)于【Linux 裸機(jī)篇(八)】I.MX6U EPIT 定時(shí)器中斷、定時(shí)器按鍵消抖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!