STM32学习笔记:系统滴答时钟SysTick

写在开篇前:

首先要明确的第一点:学习知识我们都会到网上查询各种资料,但是由于网上资料大多不全面,我们对于这些资料需要加以自身的理解并对其有所取舍,所以建议网上查来的资料只做引导、参考作用,最终确定对技术的应用还要以官方文档为准。而这个辨别资料可行性的过程是十分耗费时间的,对于此点笔者也实在无奈,如果哪些同学有更好的方法,请不吝赐教,以图共同进步。

由于本文将详细的分析SysTick整个实现过程,为了方便大家快速掌握该流程,先将结论总结如下:

1、systick是一个24位的定时器,故重装值最大值为2的24次方 = 16 777 215,要注意不要超出这个值。

2、systick是cortex_m3的标配,不是外设,不需要在RCC寄存器组打开它的时钟。

3、每次systick溢出后会置位计数标志位和中断标志位,计数标志位在计数器重装载后被清除,而中断标志位也会随着中断服务程序的响应被清除,所以这两个标志位都不需要手动清除。

4、采用使用库函数的方法,只能采用中断的方法响应定时器计时时间到,如要采用查询的方法,那只能采用设置systick的寄存器的方法。

目录

0x01、什么是时钟

0x02、STM32的时钟

0x0001)、STM32的时钟源

0x0002)、STM32的倍频、分频系统

0x03、SysTick

第一步:设置STM32系统时钟源

第二步:设置SysTick定时器

0x0001、SysTick寄存器配置

0x0002、SysTick库函数配置

0x04、源程序下载地址


SysTick是一个系统时钟定时器,属于ARM Cortex-Mx内核的一个“内设”,所有基于此内核的微控制器都带SysTick。(ST的芯片中F1系列属于Cortex-M3内核,F3与F4系列属于Cortex-M4内核)。

0x01、什么是时钟

关于这个问题 ,我们需要从 CPU的时钟说起。

计算机是一个十分复杂的电子设备。它由各种集成电路和电子器件组成,每一块集成电路中都集成了数以万计的晶体管和其他电子元件。这样一个十分庞大的系统,要使它能够正常地工作,就必须有一个指挥,对各部分的工作进行协调。各个元件的动作就是

在这个指挥下按不同的先后顺序完成自己的操作的,这个先后顺序我们称为时序。

时序是计算机中一个非常重要的概念,如果时序出现错误,就会使系统发生故障,甚至造成死机。那么是谁来产生和控制这个操作时序呢?这就是“时钟”。

“时钟”可以认为是计算机的“心脏”,如同人一样,只有心脏在跳动,生命才能够继续。不要把计算机的“时钟”等同于普通的时钟,它实际上是由晶体振荡器产生的连续脉冲波,这些脉冲波的幅度和频率是不变的,这种时钟信号我们称为外部时钟。它们被送入 CPU 中,再形成CPU时钟。不同的CPU,其外部时钟和 CPU时钟的关系是不同的。

CPU 的时钟周期通常为节拍脉冲或T周期,它是处理操作的最基本的单位。

在微程序控制器中,时序信号比较简单,一般采用节拍电位——节拍脉冲二级体制。就是说它只要一个节拍电位,在节拍电位又包含若干个节拍脉冲(时钟周期)。节拍电位表示一个CPU周期的时间,而节拍脉冲把一个CPU周期划分为几个较小的时间间隔。

根据需要,这些时间间隔可以相等, 也可以不等。

指令周期是取出并执行一条指令的时间。指令周期常常有若干个CPU周期,CPU周期也称为机器周期,由于CPU访问一次内存所花费的时间较长,因此通常用内存中读取一个指令字的最短时间来规定CPU周期。这就是说,一条指令取出阶段(通常为取指)需要一个CPU周期时间。而一个CPU周期时间又包含若干个时钟周期(通常为节拍脉冲或T周期,它是处理操作的最基本的单位)。这些时钟周期的总和则规定了 一个CPU周期的时间宽度。

总结:

1、时钟是为CPU产生时序信号而采用晶体振荡器产生的相同幅度和频率的脉冲。

2、1个指令周期包含若干个机器周期,1个机器周期又包含了若干个时钟周期,指令周期 > 机器周期 > 时钟周期

0x02、STM32的时钟

明白了什么是时钟之后,我们来分析一下STM32芯片的时钟。

STM32的时钟系统设计十分复杂,总结起来有以下两个特点

1、提供多种时钟源选择

2、可以进行倍频、分频操作。

那么为什么要设计这么复杂的时钟系统呢?主要有以下两点原因

1、倍频:考虑到电磁兼容性,如stm32f103系列芯片,最高主频可达72MHZ,如果外部直接提供一个72MHz的晶振,太高的振荡频率可能会给制作电路板带来一定的难度。

2、分频:因为STM32既有高速外设又有低速外设,各种外设的工作频率不尽相同,如同PC机上的南北桥,把高速的和低速的设备分开来管理。最后,每个外设都配备了外设时钟的开关,当我们不使用某个外设时,可以把这个外设时钟关闭,从而降低STM32的整体功耗

众所周知,微控制器(处理器)的运行必须要依赖周期性的时钟脉冲来驱动——往往由一个外部晶体振荡器提供时钟输入为始,最终转换为多个外部设备的周期性运作为末,这种时钟“能量”扩散流动的路径,犹如大树的养分通过主干流向各个分支,因此常称之为“时钟树”。在一些传统的低端 8 位单片机诸如 51,AVRPIC等单片机,其也具备自身的一个时钟树系统,但其中的绝大部分是不受用户控制的,即在单片机上电后,时钟树就固定在某种不可更改的状态(假设单片机处于正常工作的状态)。比如 51单片机使用典型的 12MHz晶振作为时钟源,则外设如IO口、定时器、串口等设备的驱动时钟速率便已经是固定的,用户无法将此时钟速率更改,除非更换晶振。这样对比起来,STM32的时钟系统设计具有明显的优势。

0x0001)、STM32的时钟源

STM32对于系统时钟提供多种选择。在STM32中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL,它们都可以作为系统时钟的来源。

系统时钟的选择是在启动时进行,复位时内部 8MHZ 的 RC 振荡器被选为默认的 CPU 时钟,随后可以选择外部的、具失效监控的 4-16MHZ 时钟;当检测到外部时钟失效时,它将被隔离,系统将自动地切换到内部的 RC 振荡器。

        1、HSI 是高速内部时钟, RC 振荡器,频率默认为 8MHz
 
 

 

2.、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz

 

 

3、LSI 是低速内部时钟,RC振荡器,频率为40kHz,可以用于驱动独立看门狗和通过程序选择驱动 RTC(RTC用于从停机/待机模式下自动唤醒系统)

 

 

4、LSE是低速外部时钟,接频率为32.768kHz的石英晶体,也可以被用来驱动RTC

 

 

5、PLL 为锁相环倍频输出,其时钟输入源可选择为HSI/2HSE或者HSE/2。倍频可选择为2~16倍, 但是其输出频率最大不得超过 72MHz

 

0x0002)、STM32的倍频、分频系统

我们先贴上STM32的时钟树图

从时钟树的分析,看到经过一系列的倍频、分频后得到了几个与我们开发密切相关的时钟。

SYSCLK:系统时钟,STM32大部分器件的时钟来源。主要由AHB预分频器分配到各个部件。

HCLK:AHB预分频器直接输出得到,它是高速总线AHB的时钟信号,提供给存储器,DMA及 Cortex内核,是Cortex内核运行的时钟,CPU主频就是这个信号,它的大小与STM32运算速度,数据存取速度密切相关。

FCLK:同样由AHB预分频器输出得到,是内核的“自由运行时钟”。“自由”表现在它不来自时钟 HCLK,因此在HCLK时钟停止时FCLK也继续运行。它的存在,可以保证在处理器休眠时, 也能够采样和到中断和跟踪休眠事件,它与HCLK互相同步。

PCLK1:外设时钟,由APB1预分频器输出得到,最大频率为36MHZ,提供给挂载在APB1总线上的外设。

PCLK2:外设时钟,由APB2预分频器输出得到,最大频率可为72MHZ,提供给挂载在APB2总线上的外设。

我们举一个实例,分析一下我们是如何得到外设GPIOF的时钟(各型号芯片略有不同),根据我上图(时钟树图片)中的红色箭头走向

首先,这里我们为了得到STM32F103系列的最高主频72MHz,我们的外部时钟是8MHz,经过9倍的倍频即可得到72MHz。首先,8M的HSE经过PLLXTPRE,直接选择 HSE 为输入,得 8(MHz)。经过PLLSRC选择,还是 8(MHz)。8MHz 经过PLLMULL的 9 倍频,8*9=72(MHz)。经过SW选择PLLCLK做为SYSCLK(系统时钟)的输入时钟,那么SYSCLK等于输送过来的72MHz。外设 GPIO 的时钟来源于APB2总线,那么经过AHB 预分频器不分频。在经过APB2 预分频器不分频。最后APB2外设 GPIO 就可以得到72MHz的时钟源了。

0x03、SysTick

前面我们分析了STM32的整个时钟系统,那么SysTick是什么呢,具体怎么使用呢?

SysTick是一个24位向下递减的系统节拍定时器(system tick timer)也叫作系统滴答时钟,具有自动重载和溢出中断功能。每计数一次所需时间为1/SYSTICK,SYSTICK是系统定时器时钟,它可以直接取系统时钟,还可以通过系统时钟8分频后获取。当定时器计数到0时,将从LOAD寄存器中自动重装定时器初值,重新向下递减计数,如此循环往复。如果开启SysTick中断的话,当定时器计数到0,将产生一个中断信号。

SysTick定时器的操作可以分为2步:

第一步:设置STM32系统时钟源

因为系统时钟频率决定HCLK频率,HCLK频率决定SysTick定时器频率

这一步由于基本上有系统启动时自行设定的,无需人工参与,所以很多介绍SysTick的文章中并没有介绍,但为了更好的理解SysTick的具体工作原理,我觉得有必要详细的介绍一下。

系统启动,设置系统时钟是通过如下函数调用过程完成的

IMPORT  SystemInit  ——>  SetSysClock()  ——> SetSysClockTo72()

IMPORT  SystemInit在文件startup_stm32f10x_xx.s文件中,该文件为系统启动文件

SystemInit ()在文件system_stm32f10x.c文件

SetSysClock()在文件system_stm32f10x.c文件

SetSysClockTo72()在文件system_stm32f10x.c文件

其中IMPORT  SystemInit表示系统启动时要调用SystemInit()这个函数

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

SystemInit()又调用SetSysClock()

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;
  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;
  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;
  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;
  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
    
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 
  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

 SetSysClock()通过#define SYSCLK_FREQ_72MHz  72000000 设定调用 SetSysClockTo72(),最终将系统时钟频率设置为72M

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
 
 /* If none of the define above is enabled, the HSI is used as System clock
    source (default after reset) */ 
}
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif

上面我们对于外部8MHZ晶振输入如何倍频到72MHZ做过解释,这里我们看一下软件上是怎么实现的(这个实现过程无需人为参与)

在SetSysClockTo72中,有如下一段操作,

/*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

通过上述操作,我们将STM32的系统时钟频率设置为72MHZ。

总结:系统会自动调用上述函数进行设置,不需要我们人为的参与,但是我们需要通过宏定义来确定系统的主频。

第二步:设置SysTick定时器

设置SysTick定时器有两种方法,一种是通过寄存器,一种是通过库函数,而库函数直接启动了SysTick定时器的中断,如果你不需要使用中断功能,为了避免对官方库文件的修改,我建议使用寄存器直接配置SysTick

0x0001、SysTick寄存器配置

我们先看一下SysTick的寄存器列表,这张表位于文件Cortex®-M3 programming manual,该文件的官方下载地址如下:

https://www.st.com/resource/en/programming_manual/cd00228163-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf

1)、STK_CTRL —— SysTick控制寄存器 

Bit 16 :COUNTFLAG:Returns 1 if timer counted to 0 since last time this was read. 如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1,。如果读取该位,该位将自动清零

Bit 2   :CLKSOURCEClock source selection 时钟源选择位

0: AHB/8

1: AHB

 Bit 1   :TICKINT: SysTick exception request enable 中断响应位 

0: Counting down to zero does not assert the SysTick exception request     计数器减到0不产生中断

1: Counting down to zero to asserts the SysTick exception request.             计数器减到0产生中断

 Bit 0   : ENABLE: Counter enable 计数器使能位     启用计数器,当ENABLE设置为1时,计数器重加载寄存器,然后倒计时。当达到0时,它将COUNTFLAG设置为1,然后根据TICKINT的值选择是否产生中断。然后,它将重新加载
再次计算,然后开始计数。
 

0: Counter disabled  关闭计数器

1: Counter enabled  开启计数器

2)、STK_LOAD —— SysTick重载寄存器

Bit 23 ~ Bit 0:共24位,加载计数值,取值范围为0x00000001-0x00FFFFFF

3)、STK_VAL    —— SysTick当前值寄存器

Bit 23 ~ Bit 0:共24位,当前计数值,取值范围为0x00000001-0x00FFFFFF,写入任何值都会将字段清除为0,并且还会清除STK_CTRL寄存器为0。

4)、STK_CALIB —— SysTick校准寄存器

Bit 31   :NOREF:NOREF 标志

0: 外部参考时钟可用

1: 外部参考时钟不可用

Bit 30   :SKEW:SKEW标志

0: 校准值是准确的10ms

1: 校准值不是准确的10ms

Bit 23 ~ Bit 0:TENMS:10ms的时间内倒计数的格数。芯片设计者应该通过Cortex-M3的输入信号提供该数值。若读取该值为0,则表示无法使用校准功能。

延时程序实例:根据上述对寄存器的描述,我们利用SysTick做一个ms延时和us延时程序

static u8  fac_us = 0;		    // 1us时间内SysTick计数器的计数值
static u16 fac_ms = 0;			// 1ms时间内SysTick计数器的计数值

/**
*@brief		初始化SysTick定时器
*@param		SYSCLK:系统时钟,系统选定为72MHz
*@return	无
*/
void systick_init (u32 sysclk)
{
    SysTick->CTRL &= 0xfffffff9;   // bit2清0,选择时钟为HCLK/8即9MHZ,bit1清0,禁止SysTick中断
	fac_us = (sysclk/8)/1000000;   // 1us计数值为72 000 000 / 1000 000
    fac_ms = (sysclk/8)/1000;      // 1ms计数值为72 000 000 / 1000
	// fac_ms = (u16)fac_us*1000;
}

/**
*@brief   微秒延时函数
*@param   time_us:要延时微秒时间数
*@return  无
*/
void delay_us(unsigned long time_us)
{   
    u32 temp;        
    SysTick->LOAD = time_us * fac_us;                       //时间加载         
    SysTick->VAL  = 0x00;                                   //清空计数器
    SysTick->CTRL = 0x01 ;                                  //开始倒数   
    do
    {
        temp = SysTick->CTRL;
    }
    while(temp & 0x01 && !(temp&(1<<16)));                  //等待时间到达
    SysTick->CTRL = 0x00;                                   //关闭计数器
    SysTick->VAL  = 0X00;                                   //清空计数器
}

/**
*@brief   毫秒延时函数
*@param   time_ms:要延时毫秒时间数
*@return  无
*/
void delay_ms(unsigned long time_ms)
{                 
    u32 temp;          
    SysTick->LOAD = (u32)time_ms * fac_ms;                  //时间加载
    SysTick->VAL  = 0x00;                                   //清空计数器
    SysTick->CTRL = 0x01 ;                                  //开始倒数
    do
    {
        temp = SysTick->CTRL;
    }
    while(temp & 0x01 && !(temp&(1<<16)));                  //等待时间到达
    SysTick->CTRL = 0x00;                                   //关闭计数器
    SysTick->VAL  = 0X00;                                   //清空计数器           
}

0x0002、SysTick库函数配置

使用库函数设置SysTick定时器,只需调用SysTick_Config(uint32_t ticks)函数即可,函数自动完成:重装载值的装载,时钟源选择,计数寄存器复位,中断优先级的设置(最低),开中断,开始计数的工作。

如果不调整SysTick时钟,那么默认SysTick_CLKSource_HCLK(HCLK)

如果需要调整SysTick时钟,则调用void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)函数来配置,该函数位于文件misc.c中。

注意:函数调用顺序,应先调用SysTick_Config(uint32_t ticks),再调用SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)。

其中SysTick_CLKSource参数有两个选择,SysTick_CLKSource_HCLK_Div8(HCLK的8分频),SysTick_CLKSource_HCLK(HCLK时钟)

SysTick_CLKSourceConfig原函数如下:

/**
  * @brief  Configures the SysTick clock source.
  * @param  SysTick_CLKSource: specifies the SysTick clock source.
  *   This parameter can be one of the following values:
  *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
  *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
  * @retval None
  */
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
}

其中assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));是对传入的参数是否有宏定义进行校验,宏定义代码如下:

#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
                                       ((SOURCE) == SysTick_CLKSource_HCLK_Div8))

如果需要调整SysTick的中断优先级,则调用void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)函数来配置,该函数位于文件core_cm3.h中。

注意:函数调用顺序,应先调用SysTick_Config(uint32_t ticks),再调用NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)。

延时程序实例:我们利用库函数做一个ms级延时程序

main函数中调用SysTick_Config()配置并启动SysTick定时器

int main(void)
{
    led_init();
    /* 使用while (1)等待SysTick配置启动成功 */
    /* 如果不更改SysTick时钟源,那么SysTick时钟为72MHz,即计数72 000次为1ms,并产生1次中断 */
    if(SysTick_Config(72000))  
    { 
        /* Capture error */ 
        while (1);
    }        
    
    while(1)
    {
        GPIO_ResetBits(GPIOC,GPIO_Pin_10);
        Delay(1000);
        GPIO_SetBits(GPIOC,GPIO_Pin_10);   
        Delay(1000);
    }
}

/**
  * @brief  Inserts a delay time.
  * @param  nTime: 延时nTime毫秒
  * @retval None
  */
void Delay(__IO uint32_t nTime)
{ 
    TimingDelay = nTime;
    while(TimingDelay != 0);
}

/**
  * @brief  在中断中调用该函数,每1ms中断1次,每次中断TimingDelay变量减1
  * @param  None
  * @retval None
  */
void TimingDelay_Decrement(void)
{
    if(TimingDelay != 0x00)
    { 
        TimingDelay--;
    }
}

/**
  * @brief  This function handles SysTick Handler.SysTick中断函数
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
    TimingDelay_Decrement();
}

至此,SysTick定时器的完整的使用方式就介绍完了。

总结:SysTick定时器的使用流程如下:

设置系统时钟 ——> 设置SysTick定时器时钟 ——> 使用SysTick寄存器设置或者调用库函数设置SysTick定时器

需要注意的点:

1、如果使用查询法产生延时,只能用寄存器设置SysTick定时器,用库函数设置SysTick定时器会产生SysTick中断。

2、使用库函数更改SysTick时钟源或者中断优先级时需要注意函数调用顺序

SysTick_Config ——> SysTick_CLKSourceConfig

SysTick_Config ——> NVIC_SetPriority

0x04、源程序下载地址

下面上传一个源程序供大家参考:

https://download.csdn.net/download/thebestleo/13191669


版权声明:本文为thebestleo原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。