在【STM32F103笔记】2、单片机中的HelloWorld——流水灯中我们曾写过一个简单的延时函数,利用空操作函数__nop()并大致计算延时时间,但这个函数并不精确,有兴趣的朋友可以再把那一篇中的程序运行结果和标准时钟比较一下。
这一篇中将使用Cortex-M3内核自带的系统时钟 (System Time)设计精确的延时函数。
SysTick
Cortex-M3内核自带一个24位的降序计数器,也就是SysTick,通常Systick是用于给实时操作系统提供准确的滴答时钟。
在这里将SysTick用于精确的计时,先介绍一下2个SysTick相关的寄存器:
- SysTick control and status register (STK_CTRL):控制和状态寄存器,下图是这个寄存器每一位的说明:
- Bit 16 COUNTFLAG:每次计数器向下自减到0的时候会自动置1,表示计数完成;
- Bit 2 CLKSOURCE:时钟来源选择,可以看出SysTick的时钟源是AHB,在第二篇中可知,系统初始化后AHB时钟为72MHz,通过这一位可以选择AHB时钟不分频或者8分频作为Systick的时钟;
- Bit 1 TICKINT:是否触发中断,触发中断则会进入SysTick_Handler函数(stm32f10x_it.c文件中);
- Bit 0 ENABLE:SysTick使能位,置1则使能SysTick,开始自减计数,清0则禁用SysTick。
- SysTick reload value register (STK_LOAD):计数器加载值寄存器,每次SysTick计数器重新开始计数时,将读取这个寄存器中的值,也就是说,计多少个数由这个寄存器控制。
由于SysTick的计数器自减操作不受其它干扰和影响,完全由其时钟决定,若时钟源选择AHB 72MHz,那么当计数器从72计数到0,相当于时间1us,因此可以使用SysTick来精确计算时间。
程序设计
程序设计思路是,首先初始化SysTick,设置固定的计数(比如720),并且每次计数完成后触发中断,这样每次触发中断就是固定的事件(10us)。
初始化SysTick——SysTick_Config库函数
同样,官方库中提供了用于SysTick配置初始化的函数:
/**
* @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 =