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定时器的主要内容,如果未能解决你的问题,请参考以下文章

ARM裸机开发:GPT定时器

EPIT定时器实验

ARM裸机开发:C语言点亮LED

ARM裸机开发:主频与时钟

ARM裸机开发:串口通信

ARM裸机开发:输入中断