注:本文属博主学习时所作笔记,内容源大参考于野火的《零死角玩转STM32F103》以及部分网络资料,笔记内容仅作为自己参考,免去频繁查询参考手册的麻烦,如有错误,还请指出!
SysTick介绍
SysTick 属于CM3内核的外设,它可以产生非常精确的延时,一般用于操作系统,用于产生一个单独的时钟节拍,相当于操作系统的心脏。
SysTick是一个24bit的向下递减的计数器,计数器每计数一次的时间为$1 \over SYSCLK$,Stm32中一般设置系统时钟为72M。当重载数值寄存器递减到0时,系统定时器则会产生中断。
SysTick—系统定时器有 4 个寄存器,一般配置时,大多操作前三个。
| 寄存器名称 |
寄存器描述 |
| CTRL |
SysTick 控制及状态寄存器 |
| LOAD |
SysTick 重装载数值寄存器 |
| VAL |
SysTick 当前数值寄存器 |
| CALIB |
SysTick 校准数值寄存器 |
CTRL
| 位段 |
名称 |
类型 |
复位值 |
描述 |
| 16 |
COUNTFLAG |
R/W |
0 |
如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。 |
| 2 |
CLKSOURCE |
R/W |
0 |
时钟源选择位,0=AHB/8,1=处理器时钟 AHB |
| 1 |
TICKINT |
R/W |
0 |
1=SysTick 倒数计数到 0 时产生 SysTick 异常请 求,0=数到 0 时无动作。也可以通过读取 COUNTFLAG 标志位来确定计数器是否递减到0。 |
| 0 |
ENABLE |
R/W |
0 |
SysTick 定时器的使能位 |
LOAD
| 位段 |
名称 |
类型 |
复位值 |
描述 |
| 23:0 |
RELOAD |
R/W |
0 |
当倒数计数至零时,将被重装载的值 |
VAL
| 位段 |
名称 |
类型 |
复位值 |
描述 |
| 23:0 |
CURRENT |
R/W |
0 |
读取时返回当前倒计数的值,写它则使之清零, 同时还会清除在 SysTick 控制及状态寄存器中的 COUNTFLAG 标志。 |
代码分析
1 2 3 4 5 6 7 8 9 10 11
| static __INLINE uint32_t SysTick_Config(uint32_t ticks){ if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); SysTick->VAL = 0; SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; return (0); }
|
固件库编程时,我们通过SysTick_Config()配置系统定时器,形参 ticks 用来设置重装载寄存器的值,最大不能超过重装载寄存器的值$2^{24}$,固件库中的宏定义提供了我们参考值:
1 2 3 4 5 6 7
| #define SYSCLK_FREQ_72MHz 72000000
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;
SysTick_Config(SystemFrequency / 1000); SysTick_Config(SystemFrequency / 100000); SysTick_Config(SystemFrequency / 1000000);
|
延时函数设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void Systick_Delay_us(uint32_t us){ uint32_t i; SysTick_Config(SystemFrequency / 1000000); for (i = 0; i<us;i++){ while(!((SysTick->CTRL)&(1<<16))); } SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; } void Systick_Delay_ms(uint32_t ms){ uint32_t i; SysTick_Config(SystemFrequency / 1000); for (i = 0; i<us;i++){ while(!((SysTick->CTRL)&(1<<16))); } SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #define __IO volatile static __IO uint32_t TimingDelay;
void Delay_us(__IO uint32_t nTime){ TimingDelay = nTime; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; while(TimingDelay != 0); } void SysTick_Init(void){ if (SysTick_Config(SystemCoreClock / 1000)){ while (1); } } void TimingDelay_Decrement(void){ if (TimingDelay != 0x00){ TimingDelay--; } }
|
1 2 3 4
| void SysTick_Handler(void){ TimingDelay_Decrement(); }
|
有关volatile的细节可参考我的这篇博文:盘点C语言中你不知道的小细节,技术尚浅,仅供参考
需要延时的时候,我们可以调用函数Delay_us()并传入具体的参数, 当然之前还需要对SysTick进行初始化,将参数传给全局变量TimingDelay,当一个计数递减周期完成,产生异常(中断),自动调用中断服务函数SysTick_Handler(void),这个函数我们可以在文件==stm32f10x_it.c==中编程,再声明一个函数用于控制多少个计时周期,每完成一个计时周期减一,直至延时完成。
延时实例:
1 2 3 4 5
| void main(){ SysTick_Init(); Delay_us(1000); { } }
|