本节介绍另外一个定时器,GPT定时器。通过GPT定时led灯的亮灭,可以输出到示波器上观察精度。
一、GPT定时器
GPT(General Purpose Timer)定时器和EPIT相比,GPT功能更加强大,有俩个捕获通道,三个输出比较通道,可以生成捕获中断,比较中断,和溢出中断。GPT定时器是向上计数的。
GTP有俩种运行模式:
1.restart模式:GPT1_CR[9] = 0。只适合与通道一。向上计数到比较事件发生,清零,重新计数。我们使用restart模式。
2.free-run模式:GPT1_CR[9] = 1。适合所有通道。即是比较事件发生,依旧向上继续计数。
GPT1_CR寄存器具体的设置:
1.GPT1_CR[15]=1软复位。
2.GPT1_CR[10]=0 不使用24M时钟。
3.GPT1_CR[9] = 0。使用restart模式。
4.GPT1_CR[8:6] = 001 使用ipg_clk时钟。66M。
5.GPT1_CR[0]=1。时钟使能位。
GPT1_PR寄存器具体的设置:
1.GPT1_PR[11:0]=000~fff。代表1到4096分频。我们设置为66分频,即0x41。
GPT1_OCR1寄存器具体的设置:
1.用于设置通道1的比较寄存器的值的。当定时器累加到这个数时,就会产生比较中断。本例程中我们不使用输出比较中断,所以将其设置为最大。
GPT1_CNT:只读寄存器,用于记录当前的计数值。
二、代码实现
1.高精度延时的原理
我们使用的是66M的时钟,使用的是66的分频,所以每秒1M个计数,通过统计GPT1_CNT计数的个数就可以知道延时的时间的长短。
2.具体代码
#include "bsp_delay.h"
void delay_short(volatile unsigned int n){
while (n--) {}
}
//大约n ms的延时
void delay(int n){
while (n--){
delay_short(0x7ff);
}
}
/*精确延时初始化*/
void precise_timer_init(){
GPT1->CR = 0; //清零
GPT1->CR = 1 << 15; //复位
while((GPT1->CR >> 15) & 0x1); //等待复位完成
GPT1->CR = 1 << 6; //设置时钟66M
GPT1->PR = 65; //设置66分频
GPT1->OCR[0] = 0xffffffff; //设置比价寄存器中的值为最大
GPT1->CR |= 1 << 0; //使能时钟
/*用于比较时钟中断实现精准定时*/
#if 0
GPT1->OCR[0] = 0x500000; //设置比价寄存器中的值为最大
GIC_EnableIRQ(GPT1_IRQn); //使能GIC中的GPT1中断
/*精确延时的中断处理函数*/
system_register_irq_handler(GPT1_IRQn, system_prescise_timer_irq_handler, NULL);
GPT1->IR |= 1 << 0; //设置中断使能
#endif
}
/*精确延时的中断处理函数*/
void system_prescise_timer_irq_handler(unsigned int gicciar, void *param)
{
static unsigned char status = 0;
if (GPT1->SR & 0x1)
{
status = !status;
led_switch(LED0, status);
}
GPT1->SR |= 1 << 0; //清除中断标志位
}
//us级延迟函数,这个函数实在是太垃圾了,中断不好吗
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级延迟函数
void delayms(unsigned int msdelay)
{ int i;
for(i = 0;i < msdelay;i++){
delayus(1000);
}
}
总结
本文实现了俩种定时方案,一种就是数定时计数,一种通过中断实现。和前面的EPIT实现相同的功能主要还是在熟悉imx6uLL芯片的各种外设。