1. 系统定时器简介
系统定时器(SysTick系统)是属于Cortex-M3 (CM3)内核,内嵌在NVIC中。
系统定时器是一个24bit的向下递减的计数器, SYSCLK 每震荡一次计数器减 1,计数器每计数一次的时间为1 / SYSCLK,一般我们设置系统时钟SYSCLK(与AHB相同)等于72M。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。
SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间SysTick的处理方式都是相同的。
系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。
2. 与SysTick相关的寄存器
2.1 CTRL
SysTick控制和状态寄存器

说明: 关于CLKSOURCE位, 当0时,时钟频率是AHB/8, 当1时,时钟频率是AHB
2.2 LOAD
SysTick重装载寄存器

2.3 VAL
SysTick当前数值寄存器。计数到了哪里可以读取该值;

2.4 CALIB
SysTick 校准数值寄存器。很少用到
3. 定时器使用案例(寄存器)
我们希望每隔1s 执行一次代码,直接让1s产生一次中断,重装载值可能比较大,所以采用1ms产生一次中断,因此先算出1ms执行多少次:
- 1/72000000秒执行一次,1/72us执行一次,1us执行72次,1ms执行72000次
void Driver_SysTick_Init(void)
{
/* 1. 配置时钟源 1=AHB(72MHz) 0=AHB/8 */
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE;
/* 2. 使能中断 */
SysTick->CTRL |= SysTick_CTRL_TICKINT;
/* 3. 定时器 1ms 产生一次中断 */
SysTick->LOAD = 72000 - 1; // -1是因为寄存器减到0不会马上产生中断,要在下一个时钟周期,所以减一
/* 4. 使能定时器 */
SysTick->CTRL |= SysTick_CTRL_ENABLE;
}
// 每1ms产生一次中断
uint16_t count = 0;
void SysTick_Handler(void)
{
count++;
if (count == 1000)
{
count = 0;
// 需要定时执行的代码
}
}为什么不用开启NVIC: 因为 SysTick 是 Cortex-M 内核的一部分,其中断通道在 NVIC 中是默认开启且不可屏蔽的,所以无需额外配置 NVIC.
4. HAL库实现
- 选择时基

- 选择时钟源

- 时钟配置

- 生成代码使用
void HAL_IncTick(void)
{
uwTick += uwTickFreq;
if (uwTick % 1000 == 0)
{
// 产生了1s的计时
// 需要定时执行的代码
}
}5. 工具类
delay.h
#ifndef __delay_h
#define __delay_h
#include "stm32f10x.h" // Device header
void Delay_us(uint16_t us);
void Delay_ms(uint16_t ms);
void Delay_s(uint16_t s);
#endifdelay.c
#include "delay.h" // Device header
void Delay_us(uint16_t us)
{
/* 设计定时器重装值 */
SysTick->LOAD = 72 * us;
/* 清除当前计数值 */
SysTick->VAL = 0;
/*设置内部时钟源(2位->1),不需要中断(1位->0),并启动定时器(0位->1)*/
SysTick->CTRL = 0x5;
/*等待计数到0, 如果计数到0则16位会置为1*/
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG));
/* 关闭定时器 */
SysTick->CTRL &= ~SysTick_CTRL_ENABLE;
}
void Delay_ms(uint16_t ms)
{
while (ms--)
{
Delay_us(1000);
}
}
void Delay_s(uint16_t s)
{
while (s--)
{
Delay_ms(1000);
}
}
1
1
1
1
1
1
1
1
1
1