使用STM32系统定时器实现精确延时函数

本文章是作者在复习stm32用系统定时器做延时函数的时候看到其他文章并没有满足我的需求,所以自己做以下笔记用于以后复习,如有错误敬请原谅。

系统定时器属于是单片机内核的定时器,嵌套在NVIC中,它是一个24位向下递减的定时器。我们查看内核手册可以看到相关信息。手册中关于系统定时器的介绍如下。

首先我们先复习stm32的时钟

在时钟树下方的解释中我们可以看到系统定时器可以用HCLK这个时钟或者该时钟的8分频,在使用默认配置下也就是可以使用72MHz和9MHz。当然我们也可以自己配置时钟来超频。

我们再来看到系统定时器的相关寄存器,相关的有4个,常用的只有3个。如下

控制寄存器只用到了4个位,剩下的位为空。表中控制寄存器第一个位是标志位,该位如果置1则表明计数器已经从重装载值递减到1,软件读取该寄存器后该位会自动清0。第二个位是时钟选择位,可以选择上述讲到72M和9M。第三个位是使能位,用来开启或者关闭定时器。

重装载寄存器就是存放重装载值。

通过当前数值寄存器可以读出当前的计数值。还有一个校准寄存器没有用到就没有列出。

现在已经知道了定时器的时钟、寄存器的作用,接下来就看看定时时间如何计算。

我们知道时间等于频率的倒数,t=1/f,所以假设我们用到的72M的频率,则记一个数的时间就是1/(72M)=1/72  us,我们在这式子前面乘一个常数k=72,这样我们计一个数就是1us,如果k=72000,则计一个数为1ms。将这个思路转化到代码上就是将重装载值乘上我们这个常数k,就可以完成us,ms级的定时。

下面附上江协科技提供的代码,结合代码跟上面的相关知识应该就可以理解了

#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 

最后还要补充一点就是在stm32的内核文件中在一开始就已经完成过一次系统定时器的初始化,代码如下:

/**
 * @brief  Initialize and start the SysTick counter and its interrupt.
 *
 * @param   ticks   number of ticks between two interrupts
 * @return  1 = failed, 0 = successful
 *
 * Initialise the system tick timer and its interrupt and start the
 * system tick timer / counter in free running mode to generate 
 * periodical interrupts.
 */
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

这里面不止初始化了三个寄存器还配置了中断优先级,所以在江科协的代码中只需要重新配置这三个寄存器就可以了。

作者:flarecannon

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32系统定时器实现精确延时函数

发表评论