一、SysTick 简介
SysTick ——系统定时器是属于 CM3 内核的一个外设,内嵌在 NVIC 中。系统定时器是一个 24 位的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 为 72MHz。当重装载数值寄存器的值递减到 0 时,系统寄存器就产生一次中断,循环往复。
二、SysTick 寄存器介绍
SysTick 系统定时器有 4 个寄存器,如下表,在配置 SysTick 产生定时的时候,只需要配置前 3 个寄存器,最后一个校准寄存器一般不需要使用
1、SysTick 控制及状态寄存器
COUNTFLAG:在上次读取此寄存器后,SysTick 如果计数到 0,则该位为 1。如果读取该位,该位将自动清 0
CLKSOURCE:时钟选择位,0=AHB/8,1=AHB
TICKINT: 1 代表 SysTick 计数到 0 时,产生异常请求,0 代表 SysTick 计数到 0 时,无动作
ENABLE:系统定时器使能位,用来使能定时器
2、SysTick 重装载数值寄存器
RELOAD: 当计数到 0 时,这个值将会被放到系统定时器上,开始计数
3、SysTick 校准数值寄存器
CURRENT:读取时,会返回当前倒计数的值,写它则使之清 0,同时还会清除在 SysTick 控制及状态寄存器中的 COUNTFLAG 标志
三、例程思路:
用系统定时器,每隔 100ms 产生一个中断,同时在中断函数中,设置一个变量 num,每进一次中断,该变量+1,并在 OLED 显示屏上显示出这个变量的值
#include "OLED7.h"
#include "Delay.h"
#include "stm32f10x_it.h"
uint32_t num = 0;// 设置全局变量,用来计数 SysTick 进入中断的次数
int main(void)
{
uint8_t i = 0;
OLED7_Init();// 初始化 OLED 显示屏
SysTick_Config(720000);//这个函数,下面会详细讲解
for (; ;)
{
OLED7_ShowNum(2, 1, num, 5);// 在显示屏的 2 行 1 列显示全局变量 num
}
return 0;
}
void SysTick_Handler(void)// SysTick 中断处理函数
{
num++;
}
SysTick _Config( ) 说明:
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
//设置重装载值,和 2^24-1 进行比较,只有小于 2^24 代码才可以继续往下走,这是因为系统定时器
//是 24 位的计数器,超过这个数值的话,肯定是没有意义的
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
// 将 Ticks 写入到 SysTick 的 LOAD 中,等计数为 0,这个值会放入到 24 位计数器里面
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
// 设置中断优先级为 15,内核中断和外设中断配置 NVIC 不一样
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
// 设置计数器为 0
SysTick->VAL = 0;
// 设置 CTRL 寄存器
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | //设置时钟源为 AHB
SysTick_CTRL_TICKINT_Msk | //设置中断开启
SysTick_CTRL_ENABLE_Msk; //ENABLE 定时器
return (0);
}
四、中断进不去的原因
因为我是用软件 SPI 来通讯 OLED 显示屏的,而当我写 SPI 函数的时候,用到了 Delay 函数,其中 Delay 函数就是用系统定时器来实现的,这就导致我每次调用一下 Delay 函数,定时器就会关断的状态,且中断也会关闭,这与 SysTick _Config( ) 的设置产生矛盾。