ARM裸机开发:GPT定时器

举报
JeckXu666 发表于 2022/01/15 01:24:48 2022/01/15
【摘要】 文章目录 ARM裸机开发:GPT定时器一、硬件平台:二、原理分析2.1 GPT定时器简介2.2 GPT有关寄存器2.2.1 GPT配置寄存器2.2.2 GPT分频寄存器2.2.3 GPT状态寄存器...

ARM裸机开发:GPT定时器

一、硬件平台:

正点原子I.MX6U阿尔法开发板

_533488159_IMG_20210803_235508_1628006109000_xg_0

二、原理分析

I.MX6U 提供了多种硬件定时器,有些定时器功能强大;本章介绍的 GPT 定时器主要用来实现高精度延时,下面对 GPT原理做个简单的分析:

2.1 GPT定时器简介

GPT 定时器是一个 32 位向上定时器 (也就是从 0X00000000 开始向上递增计数),GPT 定时器可以跟一个值进行比较,当计数器值和这个值相等的话就发生比较事件,产生比较中断

GPT 定时器有一个 12 位的分频器,可以对 GPT 定时器的时钟源进行分频

GPT 定时器特性如下:

① 一个可选时钟源的 32 位向上计数器

② 两个输入捕获通道,可以设置触发方式

③ 三个输出比较通道,可以设置输出模式

④ 可以生成捕获中断、比较中断和溢出中断

⑤ 计数器可以运行在重新启动 (restart) 或(自由运行) free-run 模式

GPT 的时钟源可选 5 个:

20211120152554

这5个时钟源对应如下:

  • ipg_clk_24M
  • GPT_CLK(外部时钟)
  • ipg_clk
  • ipg_clk_32k
  • ipg_clk_highfreq

我们选择 ipg_clk 为 GPT 的时钟源,ipg_clk 为 66MHz

GPT 定时器结构如下:

20211120153524

图中信号走线如下:

  1. 时钟源

  2. 分频器

  3. 定时器计数器

  4. 输入捕获

  5. 输入捕获

  6. 输出比较

  7. 输出比较中断

2.2 GPT有关寄存器

2.2.1 GPT配置寄存器

寄存器结构:

20211122190955

SWR(bit15):复位 GPT 定时器

FRR(bit9):运行模式选择

CLKSRC(bit8:6):GPT 定时器时钟源选择位

ENMOD(bit1):GPT 使能模式

EN(bit0):GPT 使能位

2.2.2 GPT分频寄存器

寄存器结构:

20211122191016

PRESCALER(bit11:0): 12 位分频值

2.2.3 GPT状态寄存器

寄存器结构:

20211122191047

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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。