【裸机开发】GPT 定时器(三) —— 使用GPT实现高精度延时

延时最简单粗暴的方式就是使用空循环来延时,依赖的是时钟主频(默认是396M)来计数,一旦修改了 6ull 的时钟主频,延时效果就会存在偏差。

因此我们可以使用 EPIT 或者 GPT 的计数功能实现高精度延时,EPIT 是向下计数(自减),GPT 是向上计数(自增)。


目录

一、GPT 初始化

二、延时函数delayus(us 级)

1、原理解析

2、具体实现

三、延时函数delayms(ms级)


一、GPT 初始化

和前面定时中断不一样,如果只是要实现延时功能的话,无需初始化中断,因为延时只用到了 GPT 的计数功能。

  • GPT 复位,并等待复位完成
  • 配置GPT定时器(设置计数器初始值、选择时钟源、选择工作模式)
  • 设置分频数(66 分频)
  • 启动定时器
/*
 * @description	: gpt 定时初始化(不会产生中断,只是单纯的计数)
 * @param 		: 定时器时间间隔
 * @return 		: 无
 */
void delay_init()
{
	// 禁用GPT定时器
    GPT1_CR = 0;
	GPT1_CR |= (1 << 15);
	while((GPT1_CR >> 15) & 0x01);		// 等待复位完成

	/* 
     * 配置GPT定时器
     * bit 1: 1 设置计数器初始值为0
     * bit 8-6: 001 选择时钟源ipg_clk
     * bit 9: 1 选择工作模式free-run
     */
    GPT1_CR |= ((1 << 1) | (1 << 6) | (1 << 9));

	// 分频
	GPT1_PR &= ~(0xFFF << 0);    // 低 12 bit 清零
	GPT1_PR |= (65 << 0);        // 66 分频

	// 启动定时器
    GPT1_CR |= (1 << 0);
}

二、延时函数delayus(us 级)

比如我们要延时 500ms,66MHz时钟源,66分频的条件下,500ms 转换成计数值就是 500000,因此当 delta >= 500000 时,说明延时完毕,所以问题的关键就是求从开始到现在经过了多少计数值。

1、原理解析

Free-Run 模式下,当计数器到达 0xFFFF FFFF 时就会溢出,重新从 0 开始计数。如果计数器没有溢出,从开始到现在,计数的差值如下。(计数的差值是和时间关联的)

delta = newcount - oldcount;

如果计数器溢出了,从开始到现在,计数的差值如下

delta = delta1 + delta2 = 0xFFFFFFFF - oldcount + newcount;

注意:这里的 period 与时钟周期无关

2、具体实现

判断是否移除,需要用到 GPT1_SR 的 ROV 位(bit 5)。

/*
 * @description	: 延时函数(us级)
 * @param - n	: 要延时的us数
 * @return 		: 无
 */
void delayus(unsigned int val)
{
	// 获取到当前计数器的值
	unsigned int oldcount = GPT1_CNT;
	unsigned int delta = 0;
	while (1)
	{
		unsigned int newcount = GPT1_CNT;
		// 判断是否溢出
		if ((GPT1_SR >> 5) & 0x01)			// 说明溢出了
		{
			delta = 0xFFFFFFFF - oldcount + newcount;
		}
		else
		{
			delta = newcount - oldcount;
		}

		if (delta >= val)	break;    // 延时完毕,跳出循环
	}
	GPT1_SR &= ~(1 << 5);			// 清除溢出标志位
}

解析:if (delta >= val)

66 MHz 的时钟源,66分频 =》一个时钟周期的间隔就是 1/1M = 1/10^6

val 的单位是 us:

  • 转换成 s,结果 = val / 10^6
  • 转换成对应的计数值 = 10^6 * val / 10^6  = val

因此,val (us)经过转换以后,最终的计数值就是 val

三、延时函数delayms(ms级)

/*
 * @description	: 延时函数(ms级)
 * @param - n	: 要延时的ms数
 * @return 		: 无
 */
void delayms(unsigned int val)
{
	delayus(val * 1000);
}

猜你喜欢

转载自blog.csdn.net/challenglistic/article/details/131424241