高精度定时器
我们需要高精度的延时函数,而且不随着主频的变化而改变。
STM32使用SYSTICK这个硬件定时器来实现高精度延时,因此我们可以在6U里面使用一个硬件定时器来实现高精度延时。
GPT定时器
我们使用6U的GPT定时器来实现高精度延时。
GPT定时器是32位向上计数器
GPT定时器有捕获的功能
GPT定时器支持比较输出或中断功能
GPT定时器有一个12位的分频器
GPT时钟源可以选择,这里我们使用ipg_clk=66M作为GPT的时钟源。
GPT定时器有两种工作模式:restart 和 free-run
Restart模式下:定时器计数值和比较寄存器OCR的值相等的话定时器就会重新从0开始计时。注意!只有比较通道1才有此功能。
Free-run模式:所有三个输出比较通道都适用。从0开始一直加到0xffffffff,然后重新从0开始,周而复始。
GPT_CR寄存器
Bit0为GPT使能位,为0的时候关闭GPT,为1的时候使能GPT。
Bit1确定GPT定时器计数器的初始值,为0的时候表示GPT定时器计数值默认为上次关闭的时候遗留的值,为1的话计数值为0。
Bit8~6为时钟源的选择,设置为1,表示GPT时钟源为ipg_clk=66MHz。
Bit9设置GPT定时器工作模式,为0的时候工作在restart模式,为1的时候工作在free-run模式。
Bit15软件复位。
GPT_CR寄存器的
Bit11~0
为分频值,可设置0-4095,表示1~4096分频。
GPT_SR寄存器
Bit5表示溢出发生
Bit4和Bit3分别为输入通道2和1的捕获中断标志位。
Bit2~0
,也就是OF3~OF1为比较中断。
GPT_IR寄存器,也就是中断使能寄存器
//bsp_delay.h
#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H
#include "imx6ul.h"
/* 函数声明 */
void delay_init(void);
void delayus(unsigned int usdelay);
void delayms(unsigned int msdelay);
void delay(volatile unsigned int n);
void gpt1_irqhandler(void);
#endif
//bsp_delay.c
#include "bsp_delay.h"
//延时有关硬件初始化,主要是GPT定时器,GPT定时器时钟源选择ipg_clk=66Mhz
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
/* 一下屏蔽的代码是GPT定时器中断代码,
* 如果想学习GPT定时器的话可以参考一下代码。
*/
#if 0
/*
* GPT的PR寄存器,GPT的分频设置
* bit11:0 设置分频值,设置为0表示1分频,
* 以此类推,最大可以设置为0XFFF,也就是最大4096分频
*/
GPT1->PR = 65; //设置为1,即65+1=66分频,因此GPT1时钟为66M/66=1MHz
/*
* GPT的OCR1寄存器,GPT的输出比较1比较计数值,
* 当GPT的计数值等于OCR1里面值时候,输出比较1就会发生中断
* 这里定时500ms产生中断,因此就应该为1000000/2=500000;
*/
GPT1->OCR[0] = 500000;
/*
* GPT的IR寄存器,使能通道1的比较中断
* bit0: 0 使能输出比较中断
*/
GPT1->IR |= 1 << 0;
/*
* 使能GIC里面相应的中断,并且注册中断处理函数
*/
GIC_EnableIRQ(GPT1_IRQn); //使能GIC中对应的中断
system_register_irqhandler(GPT1_IRQn, (system_irq_handler_t)gpt1_irqhandler, NULL); //注册中断服务函数
#endif
}
#if 0
/* 中断处理函数 */
void gpt1_irqhandler(void)
{
static unsigned char state = 0;
state = !state;
/*
* GPT的SR寄存器,状态寄存器
* bit2: 1 输出比较1发生中断
*/
if(GPT1->SR & (1<<0))
{
led_switch(LED2, state);
}
GPT1->SR |= 1<<0; /* 清除中断标志位 */
}
#endif
//微秒(us)级延时
//需要延时的us数,最大延时0XFFFFFFFFus
void delayus(unsigned int usdelay)
{
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 >= usdelay) //延时时间到了
break; // 跳出
}
}
}
//毫秒(ms)级延时
//需要延时的ms数
void delayms(unsigned int msdelay)
{
int i = 0;
for(i=0; i<msdelay; i++)
{
delayus(1000);
}
}
//短时间延时函数
//要延时循环次数(空操作循环次数,模式延时)
void delay_short(volatile unsigned int n)
{
while(n--){}
}
// 延时函数,在396Mhz的主频下延时时间大约为1ms
//要延时的ms数
void delay(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7ff);
}
}