ARM裸机开发:GPT定时器
ARM裸机开发:GPT定时器
一、硬件平台:
正点原子I.MX6U阿尔法开发板
二、原理分析
I.MX6U 提供了多种硬件定时器,有些定时器功能强大;本章介绍的 GPT 定时器主要用来实现高精度延时,下面对 GPT原理做个简单的分析:
2.1 GPT定时器简介
GPT 定时器是一个 32 位向上定时器 (也就是从 0X00000000 开始向上递增计数),GPT 定时器可以跟一个值进行比较,当计数器值和这个值相等的话就发生比较事件,产生比较中断
GPT 定时器有一个 12 位的分频器,可以对 GPT 定时器的时钟源进行分频
GPT 定时器特性如下:
① 一个可选时钟源的 32 位向上计数器
② 两个输入捕获通道,可以设置触发方式
③ 三个输出比较通道,可以设置输出模式
④ 可以生成捕获中断、比较中断和溢出中断
⑤ 计数器可以运行在重新启动 (restart) 或(自由运行) free-run 模式
GPT 的时钟源可选 5 个:
这5个时钟源对应如下:
- ipg_clk_24M
- GPT_CLK(外部时钟)
- ipg_clk
- ipg_clk_32k
- ipg_clk_highfreq
我们选择 ipg_clk 为 GPT 的时钟源,ipg_clk 为 66MHz
GPT 定时器结构如下:
图中信号走线如下:
-
时钟源
-
分频器
-
定时器计数器
-
输入捕获
-
输入捕获
-
输出比较
-
输出比较中断
2.2 GPT有关寄存器
2.2.1 GPT配置寄存器
寄存器结构:
SWR(bit15):复位 GPT 定时器
FRR(bit9):运行模式选择
CLKSRC(bit8:6):GPT 定时器时钟源选择位
ENMOD(bit1):GPT 使能模式
EN(bit0):GPT 使能位
2.2.2 GPT分频寄存器
寄存器结构:
PRESCALER(bit11:0): 12 位分频值
2.2.3 GPT状态寄存器
寄存器结构:
ROV(bit5):回滚标志位
IF2~IF1(bit4:3):输入捕获标志位
OF3~OF1(bit2:0):输出比较中断标志位
2.2.4 GPT计数寄存器
GPTx_CNT 保存着 GPT 定时器的当前计数值
2.3 GPT使用步骤
- 设置 GPT1 定时器
先复位再设置具体参数 - 设置 GPT1 的分频值
设置寄存器 GPT1_PR 寄存器配置分频值 - 设置 GPT1 的比较值
用到比较输出中断时设置 - 使能 GPT1 定时器
- 编写延时函数
编写延时函数进行高精度延时
三、程序编写
GPT 用于高精度延时,所以我们复制上一章的工程,修改其延时文件
bsp_delay.c 文件代码修改如下
#include "bsp_delay.h"
#include "imx6ul.h"
void delay(volatile unsigned int n)
{
while(n--)
{
volatile unsigned int i = 0x7ff;
while(i--);
}
}
void delay_init(void)
{
GPT1->CR = 0; /* 清零,bit0也为0,即停止GPT */
GPT1->CR = 1 << 15; /* bit15置1进入软复位 */
while((GPT1->CR >> 15) & 0x01); /*等待复位完成 */
/*
* GPT的CR寄存器,GPT通用设置
* bit22:20 000 输出比较1的输出功能关闭,也就是对应的引脚没反应
* bit9: 0 Restart模式,当CNT等于OCR1的时候就产生中断
* bit8:6 001 GPT时钟源选择ipg_clk=66Mhz
* bit
*/
GPT1->CR = (1<<6);
/*
* GPT的PR寄存器,GPT的分频设置
* bit11:0 设置分频值,设置为0表示1分频,
* 以此类推,最大可以设置为0XFFF,也就是最大4096分频
*/
GPT1->PR = 65; /* 设置为65,即66分频,因此GPT1时钟为66M/(65+1)=1MHz */
/*
* GPT的OCR1寄存器,GPT的输出比较1比较计数值,
* GPT的时钟为1Mz,那么计数器每计一个值就是就是1us。
* 为了实现较大的计数,我们将比较值设置为最大的0XFFFFFFFF,
* 这样一次计满就是:0XFFFFFFFFus = 4294967296us = 4295s = 71.5min
* 也就是说一次计满最多71.5分钟,存在溢出
*/
GPT1->OCR[0] = 0XFFFFFFFF;
GPT1->CR |= 1<<0; //使能GPT1
}
void delay_us(volatile unsigned int nus)
{
unsigned long oldcnt,newcnt;
unsigned long tcntvalue = 0; /* 走过的总时间 */
oldcnt = GPT1->CNT;
while(1)
{
newcnt = GPT1->CNT;
if(newcnt != oldcnt)
{
if(newcnt > oldcnt) /* GPT是向上计数器,并且没有溢出 */
tcntvalue += newcnt - oldcnt;
else /* 发生溢出 */
tcntvalue += 0XFFFFFFFF-oldcnt + newcnt;
oldcnt = newcnt;
if(tcntvalue >= nus)/* 延时时间到了 */
break; /* 跳出 */
}
}
}
void delay_ms(volatile unsigned int nms)
{
int i = 0;
for(i=0; i<nms; i++)
{
delayus(1000);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
bsp_delay.h 文件代码修改如下
#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H
void delay(volatile unsigned int n);
void delay_init(void);
void delay_us(volatile unsigned int nus);
void delay_ms(volatile unsigned int nms);
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
主函数调用延时函数进行延时
#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();
delay_init();
while (1)
{
/* code */
LED_ON();
delay_ms(1000);
LED_OFF();
delay_ms(1000);
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
四、实验现象
LED 按照 1s 的频率进行翻转
文章来源: blog.csdn.net,作者:JeckXu666,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_45396672/article/details/121479719
- 点赞
- 收藏
- 关注作者
评论(0)