【STM32单片机学习】第11章 基础重点—SysTick定时器

发布者:EnchantingEyes最新更新时间:2025-11-04 来源: bilibili关键字:STM32  单片机  SysTick  定时器 手机看文章 扫描二维码
随时随地手机看文章

本章实验的目的让读者熟悉STM32F103的SysTick定时器,SysTick定时器和NVIC一样,都属于Cortex-M3的内核外设资源。SysTick定时器比较简单,借此机会感受HAL库和寄存器之间调用关系,以及SysTick定时器的中断处理。本章阅读提示:11.1 关于(介绍STM32的SysTick定时器工作方式和寄存器,需要理解)11.2 硬件设计(SysTick定时器不涉及硬件)11.3 软件设计(讲解如何配置SysTick定时器、SysTick定时器的中断函数如何处理,需要理解)11.4 实验效果(展示实验效果,操作即可)

cut-off

11.1 关于SysTick定时器

SysTick定时器(又名系统滴答定时器)是存在于Cortex-M3的一个定时器,只要是ARM Cotex-M系列内核的MCU都包含这个定时器。使用内核的SysTick定时器来实现延时,可以不占用系统定时器,节约资源。由于SysTick是在CPU核内部实现的,跟MCU外设无关,因此它的代码可以在不同厂家之间移植。

本章将使用系统滴答定时器实现延时函数,注意SysTick用于了HAL库的毫秒级延时函数“HAL_Delay()”,不建议日常使用SysTick去作为其它用途,这里只作为演示。

SysTick定时器是一个24位递减定时器,即计数器可以从最大值224开始,每个时钟周期减1,当减到0时,会产生Systick异常,同时再自动重载定时初值,开始新一轮计数。通过设置这个定时初值,就可以实现得到指定时间。如下图 11.1.1 所示,y为定时器初值,然后随着时间增加,值逐渐减小,直至为0,再重新加载初值,如此往复,x1、x2、x3这些时间段,就是我们需要的延时时间。

图 11.1.1 Systick定时器工作示意图

假设STM32F103工作在72MHz,即72000000Hz,意味着1s时间内,会计数72000000次。那么1ms则计数72000000/1000=72000次。这个72000就可以作为系统滴答定时器的初始值,将这个值写入系统滴答定时器,定时器在每个时钟周期减1,减到0时,就刚好是1ms,同时产生中断通知,再次加载72000如此反复。HAL库提供“HAL_SYSTICK_Config()”函数去设置这个初始值。

系统滴答定时器控制寄存器比较少,整体比较简单,借助本次机会详细分析一下寄存器和HAL之间是调用关系。系统滴答定时器只有四个控制寄存器:STK_CTRL,STK_LOAD,STK_VAL和STK_CALIB。因为系统滴答定时器属于Cotex-M3内核的外设,相关寄存器介绍不在《参考手册》,而在《3_STM32F10xx Cortex-M3编程手册》,后简称《编程手册》。

  •  系统滴答定时器控制和状态寄存器(STK_CTRL)

重点关注Bit[0],用于使能系统滴答定时器,Bit[1]使能系统滴答定时器中断,Bit[2]系统滴答时钟的时钟来源。

  • 系统滴答定时器加载值寄存器(STK_LOAD)

Bit[23:0],一共24位,用来设置系统滴答定时器的初始值,因此范围为1~ 16777216。  

  • 系统滴答定时器当前值寄存器(STK_VAL)

Bit[23:0],一共24位,用来获取当前系统滴答定时器的计数值。

  • 系统滴答定时器校准值寄存器(STK_CALIB)

这个寄存器没用到,可以不用管。此外,当处理器在调试期间被暂停(halt)时,系统滴答定时器也将暂停运作。

      

在理解系统滴答定时器的工作方式,了解系统滴答定时器的寄存器基本信息后,就可以尝试编写程序了。

11.2 硬件设计

系统滴答定时器属于Cortex-M3内核资源,不涉及外部硬件电路。实验中会用到LED灯,电路设计参考前面LED点灯实验。

 

11.3 软件设计

11.3.1.1 软件设计思路

实验目的:使用系统滴答定时器实现自定义延时。

1) 分析HAL库的系统滴答定时器配置函数;

2) 初始化系统滴答定时器(设置计数初值、使能等);

3) 封装延时函数,设置系统滴答定时器中断处理函数;

4) 主函数调用验证;

本实验配套代码位于“5_程序源码4_基础重点—SysTick定时器”。

 

11.3.1.2 软件设计讲解

1) 分析HAL库的系统滴答定时器配置函数

在HAL库中,使用“HAL_SYSTICK_Config()”函数配置SysTick的初始值。

代码段 11.3.1 SysTick配置函数(stm32f1xx_hal_cortex.c)


/**


  * @brief  Initializes the System Timer and its interrupt, and starts the System Tick Timer.


  *         Counter is in free running mode to generate periodic interrupts.


  * @param  TicksNumb: Specifies the ticks Number of ticks between two interrupts.


  * @retval status:  - 0  Function succeeded.


  *                  - 1  Function failed.


  */


uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)


{


   return SysTick_Config(TicksNumb);


}

该函数调用“SysTick_Config()”函数,函数内容如下代码段 11.3.2所示。


代码段 11.3.2 SysTick配置函数(core_cm3.h)


/* ##################################    SysTick function  ############################################ */

/**

  ingroup  CMSIS_Core_FunctionInterface

  defgroup CMSIS_Core_SysTickFunctions SysTick Functions

  brief    Functions that configure the System.

  @{

 */




#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)



/**

  brief   System Tick Configuration


  details Initializes the System Timer and its interrupt, and starts the System Tick Timer.

           Counter is in free running mode to generate periodic interrupts.

  param [in]  ticks  Number of ticks between two interrupts.




  return          0  Function succeeded.


  return          1  Function failed.


  note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the

           function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>

           must contain a vendor-specific implementation of this function.

 */

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)


{


  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)

  {

    return (1UL);                                                   /* Reload value impossible */

  }


  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */


  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */

  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */

  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |

                   SysTick_CTRL_TICKINT_Msk   |

                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */

  return (0UL);                                                     /* Function successful */

}


#endif



24~27行:判断传入的SysTick初始值是否大于最大值224;


29行:设置SysTick初始值;


30行:设置SysTick中断的优先级,默认为最低;


31行:将SysTick当前计数值清零;


32~34行:设置SysTick的控制和状态寄存器,展开对应的宏,值为“(1<<2) | (1<<1) | (1)”,结合前面STK_CTRL寄存器介绍,可知这里使能了SysTick,使能了SysTick中断,时钟源为AHB。当系统时钟为72MHz时,AHB不分频,也为72MHz,则SysTick的时钟也为72MHz。


通过对“HAL_SYSTICK_Config()”函数分析,可知只需要传入SysTick初始值,其它的都默认已经设置完成了。


 


2) 初始化系统滴答定时器


假设当MCU工作在72MHz,SysTick也工作在72MHz。时钟在1s内完成周期性变化的次数叫做频率(单位:Hz),因此72MHz则表示1秒SysTick计数72000000次,即1毫秒计数72000次。


因此,如果将72000传入“HAL_SYSTICK_Config()”函数,则SysTick从72000减到0,花费时间为1毫秒,创建函数“SysTickInit()”初始化系统滴答定时器,如代码段 11.3.3 所示。


代码段 11.3.3 初始化SysTick(driver_systick.c)


/*


 *  函数名:void SysTickInit(uint32_t cycle)


 *  输入参数:cycle,设置系统滴答时钟周期


 *  输出参数:无


 *  返回值:无


 *  函数作用:初始化系统滴答时钟的频率和中断优先级


*/


void SysTickInit(uint32_t cycle)


{


    uint32_t init_t = 0;




    init_t = SystemCoreClock/cycle;




    /* 时间(单位:s)=1/频率(单位:HZ)


     * SystemCoreClock频率: 72MHz = 72,000,000


     * 即MCU 1秒会计数72,000,000次


     *       1ms则计数 72MHz/1000 = 72000次


     * 72000就是滴答时钟的初始值,它向下计数72000次,计数将变为0,就会产生一次中断


     * 滴答时钟初始值范围:1~16777216


     *


     * SystemCoreClock/1000:    1ms中断一次


     * SystemCoreClock/100000:  10us中断一次


     * SystemCoreClock/1000000: 1us中断一次


     */


    if(HAL_SYSTICK_Config(init_t) != HAL_OK)


    {


        Error_Handler();


    }




    // 设置滴答定时器中断优先级:最高


    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);


    // 使能滴答定时器中断


    HAL_NVIC_EnableIRQ(SysTick_IRQn);


}



12行:使用HAL库提供的全局变量“SystemCoreClock”获取当前系统时钟,再根据传入的cycle,计算出SysTick的初始值; 


25~28行:使用“HAL_SYSTICK_Config()”函数设置SysTick的初始值,并检测是否设置成功;


31行:设置滴答定时器中断优先级,这里设置为最高。前面分析“HAL_SYSTICK_Config()”函数,知道该函数也会设置中断优先级,这里重新设置为最高优先级,在当前示例里,SysTick中断的优先级不重要;


33行:使能SysTick中断;这里是使能NVIC,而“HAL_SYSTICK_Config()”函数使能的是SysTick;


为了方便修改SysTick的初始值,这里定义几个常见的延时周期,如代码段 11.3.4 所示。当需要延时周期为1毫秒时,传入“CYCLE_1MS”给“SysTickInit()”,则SysTick计数到零花费1毫秒




代码段 11.3.4 定义延时周期(driver_systick.h)


#define CYCLE_100MS   10


#define CYCLE_10MS    100


#define CYCLE_1MS     1000


#define CYCLE_100US   10000


#define CYCLE_10US    100000


#define CYCLE_1US     1000000



3) 封装延时函数,设置系统滴答定时器中断处理函数


创建延时函数“SysTickDelay()”,在该函数里设置自定义全局变量systick_t的初始值,SysTick每计数完一次则进入SysTick中断,将全局变量systick_t的值减1,如代码段 11.3.6 所示。一直到systick_t变为零,结束延时,如代码段 11.3.5 所示。


代码段 11.3.5 SysTick延时函数(driver_systick.c )


/*


 *  函数名:void SysTickDelay(uint16_t m)


 *  输入参数:m-延时时间


 *  输出参数:无


 *  返回值:无


 *  函数作用:滴答定时器实现的延时函数


*/


void SysTickDelay(uint32_t m)


{


    systick_t = m;


    while(systick_t != 0);


}



代码段 11.3.6 SysTick中断处理函数(stm32f1xx_it.c)


/*


  * @brief  This function handles SysTick Handler.


  * @param  None


  * @retval None


  */


void SysTick_Handler(void)


{


    HAL_IncTick();


    if(systick_t)


    {


        systick_t--;


    }


}

 


 


4) 主函数调用验证


代码段 11.3.7 SysTick延时点灯(main.c)


/*


 * 初始化滴答时钟


 * 通过改变传入参数改变滴答时钟的频率,即SysTickDelay(1)的时长


*/


SysTickInit(CYCLE_1MS);




// 初始化LED


LedGpioInit();


while(1)


{


    /* 通过延时一段时间让LED亮灭实现LED闪烁,可以通过示波器打LED的引脚反转周期,精确看时间是否与设置的一致*/


    BLED(ON);             // 点亮LED


    SysTickDelay(1000);   // 延时CYCLE_1MS*1000=1s


    BLED(OFF);            // 熄灭LED


    SysTickDelay(1000);   // 延时CYCLE_1MS*1000=1s


}



5行:初始化SysTick,这里传入CYCLE_1MS,则延时函数“SysTickDelay()”的单位为1毫秒;


7~16行:初始化LED,调用延时函数“SysTickDelay()”,传入1000,则延时为1秒;




11.4 实验效果

本实验对应配套资料的“5_程序源码4_基础重点—SysTick定时器”。打开工程后,编译,下载,可以看到蓝色LED灯间隔1秒,交替闪烁。读者可修改代码段 11.3.7 中的第5行时钟周期,或者13、15行的延时时间,改变LED灯的闪烁间隔时间。


通过LED展示SysTick的延时结果不够严谨,有条件的读者可以使用示波器或逻辑分析仪,触碰LED灯焊盘的引脚,测试翻转时间,如图 11.4.1 所示,分别修改延时时间10us、1ms、1s后逻辑分析仪测量值。


图 11.4.1 逻辑分析仪测试SysTick延时


关键字:STM32  单片机  SysTick  定时器 引用地址:【STM32单片机学习】第11章 基础重点—SysTick定时器

上一篇:STM32下载编程工具 | STM32CubeProg介绍、下载、安装和使用教程
下一篇:STM32 PC13 PC14 PC15 PB3 PB4 PA13 PA14 PA15 做普通IO口笔记

推荐阅读最新更新时间:2026-03-21 01:32

STM32单片机Systick心跳定时器的设计
Systick :系统心跳定时器,提供系统节拍 裸机程序中可作为独立的延时定时器 用途: 1.产生操作系统的时钟节拍 2.便于不同处理器之间程序移植 SysTick定时器被捆绑在NVIC中,异常号15 3.作为一个闹铃测量时间用于测量时间, 但当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。 它有四个寄存器 STK_CSR, 0xE000E010 -- 控制寄存器 STK_LOAD, 0xE000E014 -- 重载寄存器 STK_VAL, 0xE000E018 -- 当前值寄存器 STK_CALRB, 0xE000E01C -- 校准值寄存器 STM32的时钟源 选择外部时钟源时,则Systi
[单片机]
《嵌入式-STM32开发指南》第二部分 基础篇 - 第2章 Systick系统定时器(HAL)
2.1 STM32Cube新建工程 关于如何使用使用STM32Cube新建工程在前文已经讲解过了,这里直说配置GPIO部分内容。本文要实现流水灯,其实输出为初始化设置为高电平还是低电平都可以,因为流水灯需要不断反转 第1章 GPIO(HAL库) 1.GPIO配置 我们将PB0、PG6、PG7配置输出模式(高电平、低电平均可)、输出速率、上/下拉等,默认即可。 图1GPIO初始化 2.时钟源配置 图2时钟源 3.时钟配置 图3时钟配置 4.sys配置(滴答定时器配置) 图4滴答定时器 以上配置和GPIO流水灯是一样的,本文只具体讲解Systick的内容。 2.2 Systick系统定时器具体代码分析 Systic
[单片机]
STM32库函数与滴答定时器SysTick
SysTick定时器:系统滴答定时器是一个非常基本的倒计时定时器,每隔一定的时间产生一个中断,即使是系统在睡眠模式下也能工作,它使得OS在各CM3器件间的移植过程中不必修改系统定时器的代码,将移植变得简单。滴答定时器被捆绑在NVIC中,用于产生SYSTICK异常。 功能:大多数操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。比如,为多个任务给予不同数目的时间片,确保没有一个任务能一直抢占CPU;或者将每个定时器周期的某个时间范围赐予特定的任务,为系统提供各种定时功能。 下面来看一下SysTick相关的几个寄存器: 在V3.5库函数中,有关SysTick的相关配置在core_cm3.h中: 点击(此处
[单片机]
<font color='red'>STM32</font>库函数与滴答<font color='red'>定时器</font>(<font color='red'>SysTick</font>)
STM32 SYSTICK定时器常见问题
我们知道,STM32库函数里通常使用来自内核的系统定时器SYSTICK作为时基,实现计数延时。一般来讲,ST公司提供的库函数里将SYSTICK定时器配置为1ms的定时器中断,每产生1ms中断则相关中断事件计数变量加一。具体应用中我们经常会调用那个Delay()函数以实现计数定时,做延时或超时管理。 有人在阅读ST提供的LL库里的这个延时函数时,发现代码里对延时参数总是做了个加1操作,代码如下: 上图中红色代码,程序进来后就对给定的延时参数做了个加1操作,这不将1ms延时变成2ms了吗? 其实,这个地方已经有做了注释,就是为了保证有1个最小的延时等待,函数参数给定1ms的延时,经过这样加1操作后就能保证至少1ms的实际延时
[单片机]
<font color='red'>STM32</font> <font color='red'>SYSTICK</font><font color='red'>定时器</font>常见问题
STM32笔记(七)---Systick系统定时器
一、 概念 1-1 Systick简介 SysTick—系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。 因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。 1-2 Systick功能框图 counter(STK_VA
[单片机]
<font color='red'>STM32</font>笔记(七)---<font color='red'>Systick</font>系统<font color='red'>定时器</font>
STM32系统定时器-SysTick
SysTick-系统定时器是CM3内核中的一个外设,内嵌在NVIC中,所有基于CM3内核的单片机都具有这个系统定时器,系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。系统定时器是一个24bit的向下递减的计数器,计数器计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK等于72M。 因为SysTick属于内核外设,跟普通外设的中断优先级有区别,并没有抢占优先级和子优先级的说法,内核外设的中断优先级由内核SCB这个外设寄存器配置。 1.SYSTick寄存器介绍 系统定时器有4个寄存器,使用SysTick产生定时时候,只需要配置前面三个,最后一个校准寄存器不需要使用。 SysTick控制及状态寄
[单片机]
<font color='red'>STM32</font>系统<font color='red'>定时器</font>-<font color='red'>SysTick</font>
STM32系统定时器SysTick)笔记
一、简介 SysTick:系统定时器,由四个寄存器控制,存在于内核,嵌套在NVIC中,所有的Cortex-M3内核的单片机都具有这个定时器。 二、相应寄存器(这里介绍常用的几个寄存器) ①SysTick控制及状态寄存器(地址:0xE000_E010) 只有上面红色线框柱的位有效,其他位都是保留。 ②SysTick重装载数值寄存器(地址:0xE000_E014) ③SysTick当前数值寄存器(地址:0xE000_E018) 三、结合框图 图中STK_CLK对应的上面的CLKSOURCE,结合RCC时钟树: 当CLKSOURCE位为0时,时钟是AHB
[单片机]
<font color='red'>STM32</font>系统<font color='red'>定时器</font>(<font color='red'>SysTick</font>)笔记
STM32SysTick系统定时器
SysTick是STM32中的系统定时器,利用SysTick可以实现精确的延时。 SysTick—系统定时器 属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。 延时模式: SysTick的
[单片机]
<font color='red'>STM32</font>—<font color='red'>SysTick</font>系统<font color='red'>定时器</font>
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved