高精度延时函数的实现

1、用for函数实现

void udelay()
{
	int i;
	for(i=0; i<xxx; i++);
}

void test()
{
	while(1)
	{
		udelay();
		GPIO_SET(1); //拉高电平
		udelay();
		GPIO_SET(0); //拉低电平
	}
}

        在udelay函数中,用一个for循环进行延时,但是我们怎么确定xxx这个值呢?

        可以用test函数,每次udelay后就拉高一个GPIO,然后再udelay一次后拉低GPIO。并用示波器测测量出波形,通过不停的调整xxx的值,直到波形的间隔为1微妙。

        当然,这样有两个明显的缺点(1)需要使用示波器,比较麻烦(2)for循环在SDRAM和nor flash运行的速度不一样,所用的时间就不一样,所以精度就不准的。所以我们使用第二种方法


2、用定时器实现


(1)每来一个CLK,计数值减一

(2)减到0后,重新加载初始值

假设Tclk=0.1us,当定时器里面的计数值减了10,就对应了1us

比如,以jz2440的芯片为例

void timer_init()
{
	/*设置TIMER0的时钟*/
	/* Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value} 
	 *                              = 50000000 / (4 + 1) / 2
         *                              = 5000000 
         * 每减1,对应0.2us
         * 每减5,对应1us
         * 50000减到0,对应10ms
	 */
	TCFG0 = 4;   /*Prescaler 0 = 4,用于timer0,1*/
	TCFG1 &= ~0xf;/*MUX0 : 1/2*/
	
	
	/*设置TIMER0的初值*/
	TCNTB0 = 50000;  /*10Ms中断一次*/
	
	/*加载初值,启动timer0*/
	TCON |= 1<<1;   /*Update from TCNTB0 & TCMPB0*/
	
	/*设置为自动加载*/
	TCON &= ~(1<<1);
	TCON |= (1<<0) | (1<<3);  /*bit0:start  ,  bit3: auto reload*/
	
	
	/*设置中断*/
	register_irq(10, timer_irq);
	
}

/*为了保证精度,尽量少调用函数*/
void udelay(int n)
{
	int cnt = n * 5; //n us对应n*5个计数值
	int pre = TCNTO0; //当前的计数值可以从这个寄存器读
	int cur;
	int delta;

	while(cnt > 0)
	{
		cur = TCNTO0;
		if( cur <= pre )
		{
			delta = pre - cur;
		}
		else
		{
			delta = pre + (50000 - cur);//减到0后,会重新加载初始值,有可能cur大于pre
		}
		cnt = cnt - delta;
		pre = cur;
	}
}




猜你喜欢

转载自blog.csdn.net/lee_jimmy/article/details/80866631