STM32_SysTick_寄存器操作

文章目录

  • [一、SysTick 核心寄存器](#一、SysTick 核心寄存器)
    • [   SysTick 寄存器地址固定在 0xE000E010,核心 4 个寄存器:](#   SysTick 寄存器地址固定在 0xE000E010,核心 4 个寄存器:)
    • [   核心规则:](#   核心规则:)
  • [二、SysTick 寄存器编程](#二、SysTick 寄存器编程)
    • [   1、精准 us/ms 延时函数(非中断方式)](#   1、精准 us/ms 延时函数(非中断方式))
    • [   2、SysTick 周期性中断(1ms 中断)](#   2、SysTick 周期性中断(1ms 中断))
  • 三、小结

SysTick(系统滴答定时器)是 Cortex-M 内核自带的外设,无需依赖 STM32 片上外设,常用来实现精准延时、系统心跳(如 RTOS 时钟节拍)。

一、SysTick 核心寄存器

SysTick 寄存器地址固定在 0xE000E010,核心 4 个寄存器:

核心规则:

SysTick 时钟源默认是系统时钟(72MHz)(STM32F103);

递减计数:从 LOAD 值减到 0,触发 COUNTFLAG(或中断),然后自动重载;

延时计算公式:LOAD = (时钟频率 × 延时时间) - 1(减 1 是因为从 0 开始计数)。

二、SysTick 寄存器编程

1、精准 us/ms 延时函数(非中断方式)

实现微秒 / 毫秒级阻塞延时,无中断、占用 CPU 但简单高效。

c 复制代码
		#include "stm32f10x.h"
		
		// 全局变量:SysTick时钟频率(72MHz)
		#define SYSTICK_CLK 72000000
		
		/**
		 * @brief  SysTick初始化(关闭中断,仅用于延时)
		 */
		void SysTick_Init(void)
		{
		    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  // 先关闭SysTick
		    SysTick->VAL = 0;                           // 清空当前计数值
		}
		
		/**
		 * @brief  SysTick微秒延时(寄存器版)
		 * @param  us:延时微秒数(最大支持 999999us,超过需拆分)
		 */
		void SysTick_Delay_us(uint32_t us)
		{
		    uint32_t load_val;
		    
		    // 1. 计算重装载值:72MHz → 1us需要计数72次
		    load_val = (SYSTICK_CLK / 1000000) * us - 1;
		    // 防止重载值超过SysTick_LOAD_RELOAD_Msk(24位最大值)
		    if(load_val > SysTick_LOAD_RELOAD_Msk)
		    {
		        load_val = SysTick_LOAD_RELOAD_Msk;
		    }
		
		    // 2. 设置重装载值
		    SysTick->LOAD = load_val;
		    // 3. 清空当前计数值
		    SysTick->VAL = 0;
		    // 4. 开启SysTick(关闭中断,时钟源=系统时钟)
		    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
		
		    // 5. 等待计数完成(COUNTFLAG位为1)
		    while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
		
		    // 6. 关闭SysTick
		    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
		}
		
		/**
		 * @brief  SysTick毫秒延时(寄存器版)
		 * @param  ms:延时毫秒数
		 */
		void SysTick_Delay_ms(uint32_t ms)
		{
		    // 拆分长延时,避免LOAD值溢出(24位最大值约186ms@72MHz)
		    while(ms--)
		    {
		        SysTick_Delay_us(1000);
		    }
		}
		
		/**
		 * @brief  测试:LED闪烁(PC13)
		 */
		void GPIO_Init_LED(void)
		{
		    // 开启GPIOC时钟
		    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
		    // 配置PC13为推挽输出
		    GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
		    GPIOC->CRH |= GPIO_CRH_MODE13_0;
		    GPIOC->ODR |= GPIO_ODR_ODR13; // 初始熄灭
		}
		
		// 主函数测试
		int main(void)
		{
		    SysTick_Init();       // 初始化SysTick
		    GPIO_Init_LED();      // 初始化LED
		
		    while(1)
		    {
		        GPIOC->ODR ^= GPIO_ODR_ODR13; // 翻转LED
		        SysTick_Delay_ms(500);        // 延时500ms
		    }
		}

2、SysTick 周期性中断(1ms 中断)

用于系统节拍(如 RTOS 时钟、定时任务),中断方式不阻塞 CPU。

c 复制代码
		#include "stm32f10x.h"
		
		// 全局变量:1ms中断计数
		uint32_t SysTick_Count = 0;
		
		/**
		 * @brief  SysTick初始化(1ms中断)
		 */
		void SysTick_IRQ_Init(void)
		{
		    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  // 关闭SysTick
		    SysTick->VAL = 0;                           // 清空计数值
		
		    // 1. 设置1ms重装载值:72MHz → 1ms需要72000次计数
		    SysTick->LOAD = (SYSTICK_CLK / 1000) - 1;
		
		    // 2. 配置NVIC(SysTick中断优先级)
		    // SysTick是内核中断,优先级由SCB->SHPR3的bit24-31配置
		    SCB->SHPR3 |= (0x20 << 24);  // 抢占优先级2(高4位有效)
		
		    // 3. 开启SysTick中断 + 开启SysTick + 时钟源=系统时钟
		    SysTick->CTRL = SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
		}
		
		/**
		 * @brief  SysTick中断服务函数(内核中断,名称固定)
		 */
		void SysTick_Handler(void)
		{
		    // 清除中断标志(读COUNTFLAG自动清,或写VAL=0)
		    SysTick->VAL = 0;
		    // 业务逻辑:1ms计数+1
		    SysTick_Count++;
		}
		
		/**
		 * @brief  基于SysTick计数的ms延时(非阻塞版)
		 * @param  ms:延时毫秒数
		 */
		void SysTick_Delay_ms_IRQ(uint32_t ms)
		{
		    uint32_t target = SysTick_Count + ms;
		    while(SysTick_Count < target);
		}
		
		// 主函数测试
		int main(void)
		{
		    SysTick_IRQ_Init();   // 初始化SysTick中断(1ms)
		    GPIO_Init_LED();      // 复用上面的GPIO_Init_LED函数
		
		    while(1)
		    {
		        GPIOC->ODR ^= GPIO_ODR_ODR13; // 翻转LED
		        SysTick_Delay_ms_IRQ(500);    // 基于中断的500ms延时
		    }
		}

三、小结

SysTick 寄存器编程核心:配置LOAD(重装载值)→ 清空VAL → 控制CTRL(开启 / 中断);

非中断版延时简单高效,适合短延时;中断版不阻塞 CPU,适合系统节拍;

注意 24 位 LOAD 寄存器的溢出限制,长延时需拆分处理,且时钟源需与计算值匹配。

相关推荐
DLGXY2 小时前
STM32(二十四)——PWR电源控制
stm32·单片机·嵌入式硬件
csg11072 小时前
PIC单片机高阶实战(五):PIC32MX系列的数据存储
单片机·嵌入式硬件·物联网
爱喝纯牛奶的柠檬3 小时前
基于STM32的GPS NMEA解析驱动设计与实现
stm32·单片机·嵌入式硬件
大志出奇迹4 小时前
STM32常用变量类型位数及取值范围
stm32·单片机·嵌入式硬件
LCG元5 小时前
STM32项目实战:基于STM32F103的智能循迹避障小车
stm32·单片机·嵌入式硬件
luoshanxuli20105 小时前
ESP-IDF 简介
嵌入式硬件·物联网·系统架构
羽获飞5 小时前
从零开始学嵌入式之STM32——27.基于STM32F103C8T6MCU的寄存器方式实现按键调整PWM占空比,调整输出功率
stm32·单片机·嵌入式硬件
学嵌入式的小杨同学5 小时前
STM32 进阶封神之路(十五):DHT11 单总线实战 —— 温湿度检测从时序解析到代码落地(库函数 + 寄存器)
vscode·stm32·单片机·嵌入式硬件·mcu·智能硬件·pcb工艺
QYQ_11276 小时前
嵌入式学习——51单片机
嵌入式硬件·学习·51单片机