SysTick 叫做系统滴答时钟、系统定时器,是系统内核中的一个片上外设被捆绑在 NVIC 中,用来产生 SYSTICK 异常 SysTick_Handler(异常号:15)。
SysTick 是一个 24bit 向下递减的计数器,当计到 0 时,从 RELOAD 寄存器中自动装载定时初值,并触发中断,进行周期性任务。
系统定时器的用途
- 没有操作系统:只用于延时(使用内核的SysTick定时器来实现延时,可以不占用系统定时器,节约资源)
- 有操作系统:(ucos2、ucos3、freertos为操作系统提供精准的系统时基(1ms~50ms)
SysTick 时钟来源
可以来自两个地方:
- 内核时钟:AHB 时钟 8 分频
- 内核时钟的 1/8:HCLK 时钟 / (AHB 时钟)
通常情况下我们一般选择内核时钟,因为他的精度更高
时钟树
SysTick 寄存器
操作 SysTick 通常通过直接访问寄存器来完成。SysTick 是一个硬件模块,其功能由特定的寄存器控制。
工作流程
SysTick 的工作流程如下:
- 配置时钟源
- 选择 HCLK 或 HCLK/8 作为计数器的时钟输入。
- 加载重载值
- 将所需的计时周期转换为计数值,写入 LOAD 寄存器。
- 计数周期为 LOAD + 1 个时钟周期。
- 计数递减
- 每个时钟周期,计数器递减 1。
- 当前值保存在 VAL 寄存器。
- 计数到零
- 当计数器递减到零:
- 如果启用了中断,会触发中断处理程序。
- 自动从
LOAD
寄存器重新加载初始值,继续计数。
实现
在 ARM32 架构中通常都帮我们写好了相关配置,我们只需要调用 SysTick_Config 这个函数并传入周期值,他会在计数到 0 时自动触发中断,我们在相应的中断处理函数中进行操作即可;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #ifndef SYS_TICK_H #define SYS_TICK_H
#include <stdint.h>
void systick_config(void);
void delay_1ms(uint32_t count); void delay_1us(uint32_t count);
void delay_decrement(void);
#endif =================================================== #include "gd32f4xx.h" #include "systick.h"
volatile static uint32_t delay;
void systick_config(void) { if(SysTick_Config(SystemCoreClock / 1000000U)) { while(1) { } } NVIC_SetPriority(SysTick_IRQn, 0x00U); }
void delay_1ms(uint32_t count) { delay = count * 1000; while(0U != delay) { } }
void delay_1us(uint32_t count) { delay = count; while(0U != delay) { } }
void delay_decrement(void) { if(0U != delay) { delay--; } } =========================================== void SysTick_Handler(void) {
delay_decrement(); }
void TimingDelay_Decrement(void) { if (uwTimingDelay != 0x00) { uwTimingDelay--; } }
|