ARM裸机开发:EPIT定时器
Posted JeckXu666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARM裸机开发:EPIT定时器相关的知识,希望对你有一定的参考价值。
ARM裸机开发:EPIT定时器
一、硬件平台:
正点原子I.MX6U阿尔法开发板
二、原理分析
I.MX6U 提供了多种硬件定时器,有些定时器功能强大;本章 EPIT 定时器是其最基本的定时器!
2.1 EPIT 定时器简介
EPIT 全称:Enhanced Periodic Interrupt Timer(增强的周期中断定时器),用于完成周期性中断定时;
在 STM32 中,单片机的定时器除了周期性中断定时之外,还可以进行输入捕获和 PWM 输出功能,而 EPIT 仅支持周期性中断定时功能;
EPIT 是一个 32 位定时器,有如下特点:
- 时钟源可选的 32 位向下计数器
- 12 位的分频值
- 当计数值和比较值相等的时候产生中断
定时器结构如图:
其原理路线如下:
通过 1 选择时钟源,经过 12 位的分频器 2 进行分频,分频后的时钟提供给 32 位的计数寄存器 3,计数寄存器(EPIT_CNR)向下计数,通过比较器 4 和 32 位的比较寄存器(EPIT_CMPR)进行比较,到达计数周期后从加载寄存器(EPIT_LR)重新加载计数值,同时产生一个比较事件 6,也可以设置引脚输出,如果设置了的话就会通过指定的引脚输出信号,对应图中 5 ;
EPIT 定时器有两种工作模式:
- set-and-forget 模式:
在此模式下 EPIT 的计数器从加载寄存器 EPITx_LR 中获取初始值,不能直接向计数器寄存 器写入数据,只要计数器计数到 0,那么就会从加载寄存器 EPITx_LR 中重新 加载数据到计数器中
- free-running 模式:
作在此模式下,当计数器计数到0以后会重新从0XFFFFFFFF开始计数,并不是从加载寄存器EPITx_LR中获取数据
2.2 EPIT 主要寄存器
EPIT 的配置寄存器 EPITx_CR
主要位:
位 | 功能 |
---|---|
CLKSRC(bit25:24) | EPIT 时钟源选择位 0 的时候关闭时钟源 1 的时候选择选择Peripheral 时钟(ipg_clk) 2 的时候选择 High-frequency 参考时钟(ipg_clk_highfreq) 3 的时候选择 Low-frequency 参考时钟(ipg_clk_32k) |
PRESCALAR(bit15:4) | EPIT 时钟源分频值,可设置范围 0~4095,分别对应 1~4096 分频 |
RLD(bit3) | EPIT 工作模式 0 的时候工作在 free-running 模式 1 的时候工作在 setand-forget 模式 |
OCIEN(bit2) | 比较中断使能位 0 的时候关闭比较中断 1 的时候使能比较中断 |
ENMOD(bit1) | 设置计数器初始值 0 时计数器初始值等于上次关闭 EPIT 定时器以后计数器里面的值 1 的时候来源于加载寄存器 |
EN(bit0) | EPIT 使能位 0 的时候关闭 EPIT 1 的时候使能 EPIT |
EPITx_SR 标志寄存器:
只有一个位有效,那就是 OCIF (bit0),这个位是比较中断标志位,为 0 的 时候表示没有比较事件发生,为 1 的时候表示有比较事件发生。
比较中断发生以后需要手动清除此位,此位是写 1 清零的
2.3 EPIT 使用方式
使用步骤流程如下:
- 设置 EPIT1 的时钟源
设置寄存器 EPIT1_CR 寄存器的 CLKSRC(bit25:24)位,选择 EPIT1 的时钟源 - 设置分频值
设置寄存器 EPIT1_CR 寄存器的 PRESCALAR(bit15:4)位,设置分频值 - 设置工作模式
设置寄存器 EPIT1_CR 的 RLD(bit3)位,设置 EPTI1 的工作模式 - 设置计数器的初始值来源
设置寄存器 EPIT1_CR 的 ENMOD(bit1)位,设置计数器的初始值来源 - 使能比较中断
我们要使用到比较中断,因此需要设置寄存器 EPIT1_CR 的 OCIEN(bit2)位,使能比较中断 - 设置加载值和比较值
设置寄存器 EPIT1_LR 中的加载值和寄存器 EPIT1_CMPR 中的比较值,通过这两个寄存器就可以决定定时器的中断周期 - EPIT1 中断设置和中断服务函数编写
使能 GIC 中对应的 EPIT1 中断,注册中断服务函数,如果需要的话还可以设置中断优先级。最后编写中断服务函数 - 使能 EPIT1 定时器
通过寄存器 EPIT1_CR 的 EN(bit0)位来设置
三、程序编写
本节在上一章按键输入中断的过程下继续扩展,先复制一遍工程,然后添加 bsp_epit 文件夹和模块
模块 .h 头文件:
#ifndef __BSP_EPIT_H
#define __BSP_EPIT_H
#include "imx6ul.h"
void epit_init(unsigned int frac,unsigned int value);
void epit_irqhandler(void);
#endif
模块 .c 文件:
#include "bsp_epit.h"
#include "bsp_int.h"
#include "bsp_led.h"
//初始化函数
void epit_init(unsigned int psc,unsigned int value)
{
if(psc>0xfff)
psc=0xfff;
EPIT1->CR = 0;
EPIT1->CR = (1<<24 | psc<<4 | 1<<3 | 1<<2 | 1<<1);
EPIT1->LR = value;
EPIT1->CMPR = 0;
GIC_EnableIRQ(EPIT1_IRQn);
system_register_irqhandler(EPIT1_IRQn,
(system_irq_handler_t)epit_irqhandler,
NULL);
EPIT1->CR = 1<<0;
}
//定时器中断回调函数
void epit_irqhandler(void)
{
static unsigned char sta = 0;
sta = !sta;
if(EPIT1->SR & (1<<0))
{
if(sta)
LED_ON();
else
LED_OFF();
}
EPIT1->SR |= 1<<0;
}
主函数代码:
#include "bsp_led.h"
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_exit.h"
#include "bsp_epit.h"
#include "imx6ul.h"
int main(void)
{
CLK_INIT();
int_init();
BSP_KEY_INIT();
LED_INIT();
exit_init();
//设置定时器的分频为1,加载寄存器值为 66000000/2=33000000
//即定时器中断周期为 500ms
epit_init(0,66000000/2);
while (1)
{
/* code */
delay(100);
}
return 0;
}
修改 Makefile 添加编译路径:
make 一下,编译通过,下载程序
四、实验现象
可以看到 LED 灯周期性的闪烁,跳变间隔约 0.5 S
以上是关于ARM裸机开发:EPIT定时器的主要内容,如果未能解决你的问题,请参考以下文章