STM32学习6 SysTick系统定时器

  • 一、SysTick概念
  • 1. 概念
  • 2. 工作过程
  • 二、SysTick 使用
  • 1. **初始化 SysTick 寄存器**
  • 2. **计数器开始计数**
  • 3. **生成中断请求**
  • 4. **中断处理**
  • 5. **中断服务程序执行**
  • 6. **重复周期**
  • 三、SysTick寄存器
  • 1. **SysTick 控制和状态寄存器 (CTRL)**
  • 2. **SysTick 重装载值寄存器 (LOAD)**
  • 3. **SysTick 当前值寄存器 (VAL)**
  • 4. **SysTick 校准值寄存器 (CALIB)**:
  • 四、SysTick 库函数
  • 1. `void SysTick_Config(uint32_t ticks)`
  • 2. `void SysTick_Handler(void)`
  • 3. `void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)`
  • 4. `uint32_t SysTick_Config2(uint32_t ticks)`
  • 5. `void SysTickDelay(uint32_t us)`
  • 五、延时代码实现:
  • 1. sys_tick_utils.c
  • 2. main.c


一、SysTick概念

1. 概念

SysTick 是 Cortex-M 内核中的一个系统定时器,经常被用作系统中断控制器的基础,或者作为操作系统的时间片轮转机制的基准。
SysTick可以取系统时钟(72M),还可以把系统时钟8分频后(9M)获取。

2. 工作过程

SysTick 会定时产生中断请求,当计数器达到设定值时,SysTick会触发一个SysTick定时器中断,向NVIC发出中断请求。

NVIC负责中断的优先级管理、中断处理函数的调用和中断嵌套等工作 。 当SysTick定时器中断发生时,NVIC会对中断进行处理。

SysTick 和NVIC组成了典型的生产者-消费者关系。

二、SysTick 使用

1. 初始化 SysTick 寄存器

在使用 SysTick 之前,需要通过配置 SysTick 寄存器来初始化它,包括设置:

  • 计数器初值、
  • 选择时钟源
  • 使能 SysTick 定时器。

2. 计数器开始计数

SysTick 定时器被使能后,计数器就开始从初始值开始递减。

3. 生成中断请求

当 SysTick 定时器的计数器值减为零时,会触发一个 SysTick 中断请求,向 NVIC 发送中断请求信号。

4. 中断处理

SysTick 中断请求被 NVIC 捕获,并根据其优先级和其他中断请求的优先级进行调度。如果 SysTick 中断被选为最高优先级的中断,系统会立即响应并执行 SysTick 中断服务程序。

5. 中断服务程序执行

SysTick 中断服务程序会执行用户定义的操作,例如更新系统时间、处理定时任务或执行周期性的操作。

6. 重复周期

一旦 SysTick 中断服务程序执行完毕,SysTick 定时器会自动重置并重新开始计数,进入下一个周期,继续循环上述过程。

三、SysTick寄存器

1. SysTick 控制和状态寄存器 (CTRL)

用于配置 SysTick 定时器的工作模式、使能定时器和中断,并提供定时器当前状态的查询功能。具体的控制位包括:


名称

描述

位 0

ENABLE

使能 SysTick 定时器。

位 1

TICKINT

使能 SysTick 异常(中断)请求。

位 2

CLKSOURCE

SysTick 时钟源选择:0 = 外部时钟(HCLK),1 = 处理器时钟(SYSCLK)。

位 3-15

保留

未来使用保留位。

位 16

COUNTFLAG

如果自 SysTick 计时器上次读取此寄存器以来计数为 0,则返回 1,否则返回 0。

位 17-31

保留

未来使用保留位。

2. SysTick 重装载值寄存器 (LOAD)

用于设置 SysTick 定时器的重装载值,即定时器计数器的初始值。当计数器减到零时,会触发中断请求,并根据加载寄存器的值重新装载计数器。

3. SysTick 当前值寄存器 (VAL)

用于读取或写入当前 SysTick 定时器的计数器值。

  • 在读取该寄存器时,会返回当前计数器的剩余值;
  • 在写入该寄存器时,可以清零计数器的值。


名称

描述

位 0-31

CURRENT

当前计数值。读取此寄存器可以获取当前 SysTick 计数器的值。

4. SysTick 校准值寄存器 (CALIB):

用于读取 SysTick 定时器的校准值,包括重装载值 (TENMS) 和时钟源的准确度 (SKEW、NOREF)。这些值用于校准定时器的溢出时间,以保证其在不同系统上的准确性。


名称

描述

位 0-23

TENMS

外部时钟周期数(SysTick 时钟频率的十分之一)。

位 24

SKEW

SysTick 失真标志。在定时器滴答发生时间上存在周期性的偏移时,此标志被设置。

位 30

NOREF

无外部参考时钟标志。当 SysTick 使用外部时钟但未提供时,此标志被设置。

位 31

RESERVED

保留位。

四、SysTick 库函数

1. void SysTick_Config(uint32_t ticks)

  • 功能:配置 SysTick 定时器的装载值,用于设定定时器的周期。
  • 参数:
  • ticks:定时器的装载值,即每隔多少个时钟周期产生一次定时中断。在 STM32 中,通常取值为 SystemCoreClock / desired_frequency - 1,其中 desired_frequency 是期望的定时中断频率。

2. void SysTick_Handler(void)

  • 功能:SysTick 中断处理函数。当定时器计数器减到 0 时,会触发 SysTick 中断,执行该函数。在该函数中可以编写定时中断的处理代码。

3. void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

  • 功能:配置 SysTick 定时器的时钟源。
  • 参数:
  • SysTick_CLKSource:时钟源选择,可以是 SysTick_CLKSource_HCLK(外部时钟源)或 SysTick_CLKSource_HCLK_Div8(外部时钟源分频 8)。

4. uint32_t SysTick_Config2(uint32_t ticks)

  • 功能:配置 SysTick 定时器的装载值,并返回设置成功与否的状态。
  • 参数:
  • ticks:定时器的装载值,即每隔多少个时钟周期产生一次定时中断。
  • 返回值:配置成功返回 0,否则返回非零值。

5. void SysTickDelay(uint32_t us)

  • 功能:提供微秒级别的延时功能。注意,这个函数是一个简单的延时函数,可能不够精确,最好使用硬件定时器来实现更精确的延时。

五、延时代码实现:

1. sys_tick_utils.c

#include "stdint.h"
#include "sys_tick_utils.h"
#include "system_stm32f10x.h"

// 每 us 跳动次数
u8 tick_us;
// 每 ms 跳动次数
u16 tick_ms;

/**
 * SysTick初始化
 * @param SYSCLK 频率,一般值72
*/
void sys_tick_init(u8 SYSCLK){
	// 设置时钟源, 使用系统时钟的八分频
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    // 72 / 8 = 9 1us跳到次数
    tick_us = SYSCLK / 8;
    // 1ms 跳到次数
    tick_ms = (u16)tick_us * 1000;
}
/**
 * 微秒延时
*/
void delay_us(u32 us){
    u32 temp;
    // 重装载初始值
    SysTick->LOAD = us * tick_us;
    // 清除当前寄存器的值
    SysTick->VAL= 0x00;
    // 打开计时器,最低位开启
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
    // 倒计时,通过CTRL第16位来判断
    do{
        temp = SysTick->CTRL;
    }while((temp&0x01) && !(temp&(1<<16)));
    // 判断 CTRL 第16位
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
    // 清空计时器
    SysTick->VAL = 0x00; 
}
/**
 * 毫秒延时
*/
void delay_ms(u32 ms)
{
    delay_us(ms*1000);
}
/**
 * 秒延时
*/
void delay_second(u32 second){
    for(int i=0;i<second;i++){
        delay_ms(1000);
    }
}

2. main.c

#include "gpio_utils.h"
#include "rcc_utils.h"
#include "stm32f10x.h"
#include "sys_tick_utils.h"

// 主函数
int main(void)
{
    GPIO_Configuration(); //调用GPIO配置函数
	sys_tick_init(72);
	
    while (1) //无限循环
    {
			delay_ms(500);
			GPIO_ResetBits(GPIOC, GPIO_Pin_0);
			delay_ms(500);
			GPIO_SetBits(GPIOC, GPIO_Pin_0);
    }
}

示例代码实现LED每秒闪烁一次的功能。
代码开源地址:
https://gitee.com/xundh/stm32_arm_learn