STM32系统定时器SysTick,delay的精确编写

SYsTick叫系统滴答时钟,外围设备,24位计数器
查看《Cortex M3与M4权威指南》PDF,有关于系统定时器的说明
M4可以使用函数
uint32_t SysTick_Config(uint32_t ticks);
如果一秒想触发一千次中断,则填 SystemCoreClock/1000 ,系统内核时间1s/1000,相当于一毫秒触发一次中断

中断服务函数

		void SysTick_Handler(void)
		{
				/*实现逻辑代码,以下例子为led灯的闪烁*/
				static uint32_t cut = 0;
				cnt++;

				//到达500毫秒时,翻转led引脚的电平
				if(cnt == 500)
				{
					cnt = 0;
					PFout(9) ^= 1;	//位带操作,通过寄存器地址直接控制引脚
				}
		}

delay_ms()和delay_us()的编写
参考《Cortex M3与M4权威指南》P353有详细说明,当不想使用SysTick_Config(uint32_t ticks)函数时,可以直接对寄存器操作

delay_ms(uint32_t n)
{
	SysTick->CTRL = 0; //关闭系统定时器
	SysTick->LOAD = (168000000/1000)*n;	//填写计数值,一毫秒乘以定时数
	SysTick->VAL = 0;	//清空当前的值和计数标志位
	SysTick->CTRL = 5;	//选择时钟启动,5为系统定时器
	while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
	SysTick->CTRL = 0;	//关闭定时器
}

以上代码是直接修改参考代码得到,但是硬件有最大定时时间限制
1000ms 最大定时时间
—————— = ————————
168000000Hz 2^24

最大定时时间 = 99.86ms
故当延时500ms时超出范围,定时器工作异常。
SysTick->CTRL = 5; //选择HCLK时钟源启动,5为系统定时器,系统定时器为168MHz
SysTick->CTRL = 1; //选择HCLK/8时钟源启动,5为系统定时器,系统定时器为168MHz/8 = 21MHz
当时钟源发生改变,最大定时时间随之发生改变

代码优化:可以实现任意时间的延时

delay_ms(uint32_t n)
{
	while(n--)
	{
		SysTick->CTRL = 0; //关闭系统定时器
		SysTick->LOAD = (168000000/1000);	//定时一毫秒
		SysTick->VAL = 0;	//清空当前的值和计数标志位
		SysTick->CTRL = 5;	//选择时钟启动,5为系统定时器
		while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
		SysTick->CTRL = 0;	//关闭定时器
	}
}

//微秒延时同理
delay_us(uint32_t n)
{
	while(n--)
	{
		SysTick->CTRL = 0; //关闭系统定时器
		SysTick->LOAD = (168000000/1000000);	//定时一微秒
		SysTick->VAL = 0;	//清空当前的值和计数标志位
		SysTick->CTRL = 5;	//选择时钟启动,5为系统定时器
		while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
		SysTick->CTRL = 0;	//关闭定时器
	}
}

代码升级:变量的运算和定时器的开关都会耗费时间,当时间精准度要求较高的时候,要尽量减少代码的数值运算和定时器的开关,实现定时时间更加精准。

delay_ms(uint32_t mn)
{
	uint32_t m, n;
	m = mn/500;	//获取有多少个500ms
	n = mn%500;		//少于500ms的部分

	while(m--)
	{
		SysTick->CTRL = 0; //关闭系统定时器
		SysTick->LOAD = 10500000;	//定时一微秒,写具体的计算数值,减少计算时间	(21000000/1000)*500
		SysTick->VAL = 0;	//清空当前的值和计数标志位
		//选择时钟启动,5为HCLK系统定时器,1为HCLK/8 八分频,必须使用1,500ms超出 HCLK 的定时范围,在 HCLK/8 范围内
		SysTick->CTRL = 1;
		while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
		SysTick->CTRL = 0;	//关闭定时器
	}
	
	if(n)
	{
		SysTick->CTRL = 0; //关闭系统定时器
		SysTick->LOAD = 21000*n;	//定时一微秒,写具体的计算数值,减少计算时间	(21000000/1000)*n
		SysTick->VAL = 0;	//清空当前的值和计数标志位
		//选择时钟启动,5为HCLK系统定时器,1为HCLK/8 八分频,必须使用1,500ms超出 HCLK 的定时范围,在 HCLK/8 范围内
		SysTick->CTRL = 1;
		while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
		SysTick->CTRL = 0;	//关闭定时器
	}
}

//微秒延时同理
delay_us(uint32_t mn)
{
	uint32_t m, n;
	m = mn/500;	//获取有多少个500us
	n = mn%500;		//少于500us的部分

	while(m--)
	{
		SysTick->CTRL = 0; //关闭系统定时器
		SysTick->LOAD = 84000;	//定时一微秒,写具体的计算数值,减少计算时间	(168000000/1000000)*500
		SysTick->VAL = 0;	//清空当前的值和计数标志位
		SysTick->CTRL = 5;	//选择时钟启动,5为HCLK系统定时器,1为HCLK/8 八分频
		while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
		SysTick->CTRL = 0;	//关闭定时器
	}
	
	if(n)
	{
		SysTick->CTRL = 0; //关闭系统定时器
		SysTick->LOAD = 168*n;	//定时一微秒,写具体的计算数值,减少计算时间	(168000000/1000000)*n
		SysTick->VAL = 0;	//清空当前的值和计数标志位
		SysTick->CTRL = 5;	//选择时钟启动,5为HCLK系统定时器,1为HCLK/8 八分频
		while(SysTick->CTRL & 0x00010000 == 0);	//死循环,等待计数完毕
		SysTick->CTRL = 0;	//关闭定时器
	}
}

你可能感兴趣的:(STM32)