本文章是作者在复习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 */
}
这里面不止初始化了三个寄存器还配置了中断优先级,所以在江科协的代码中只需要重新配置这三个寄存器就可以了。