SysTick——系统定时器(标准库)

1、STM32F4的SYSTick定时器

STM32F4系统定时器SYSTick是属于内核CM4的一个外设,内嵌在NVIC中。所有基于CM4的单片机都具有这个系统定时器,使得软件能够在CM4单片机中可以很容易的移植。

系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

系统定时器是一个24bit的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK。当重装载数值寄存器的值递减到0时,系统定时器就产生一个中断,以此循环往复。

2、SYSTick的寄存器

SYSTick系统定时器有四个寄存器。在使用SYSTick产生定时时,一般只需要配置前三个寄存器,最后一个校准寄存器不需要使用。

   CTRL              SYSTick控制及状态寄存器

   LOAD             SYSTick重装载数值寄存器

   VAL                 SYSTick当前数值寄存器

   CALIB             SYSTick校准数值寄存器

3、SYSTick配置库函数

(1)库函数解析

SYSTick是属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件core_cm4.h中。

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks);

使用固件库编程的时候,我们只需要调用库函数SysTick_Config()即可。

        形参ticks用来设置重装载数值寄存器的值,最大值为2^24 = 16777216。

        返回值  0,设置成功    1,设置失败。

SysTick_Config()库函数主要配置了SYSTick中的三个寄存器:LOAD/VAL/CTRL。其中还调用了NVIC_SetPriority()来配置系统定时器的中断优先级。由于SYSTick属于内核外设,跟普通外设的中断优先级有区别,并没有抢占优先级和子优先级的说法。在STM32F407中,内核外设的中断优先级由内核SCB这个外设的寄存器:SHPPx(x = 1,2,3)来配置。在STM32F407中,只有高四位有效,中断优先级可编程为0~15,只有16个可编程优先级。

        标准库的函数原型:

__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 */
}

在系统定时器中,配置优先级为 (1UL « __NVIC_PRIO_BITS) - 1UL),其中宏 __NVIC_PRIO_BITS 为 4,那计算结果就等于 15,可以看出系统定时器此时设置的优先级在内核外设中是最低的。

  #ifndef __NVIC_PRIO_BITS
    #define __NVIC_PRIO_BITS          4
    #warning "__NVIC_PRIO_BITS not defined in device header file; using default!"
  #endif

SYSTick初始化函数由用户自己编写,里面调用了SysTick_Config()这个固件函数,通过设置该函数的形参,就决定了系统定时器经过多少时间就产生一次中断。

void SysTick_Init(void)
{
    if(SysTick_Config(SystemCoreClock/100000))   //10us
    {
        while(1);
    }
} 

(2)SYSTick相关计算

SYSTick中断时间计算

SYSTick定时器的计数器是向下递减计数的,计数一次时间 T = 1/AHBCLK

当重载寄存器中的值VALUE减到0的时候,产生中断。

中断一次的时间 T=VALUE/AHBCLK。

如果AHBCLK设置为168MHz,VALUE值设置为168,则中断时间为1us。

VALUE值设置为1680,则中断时间为10us.

VALUE值设置为168000,则中断时间为1ms。

static __IO uint32_t TimingDelay;

void systick_init(void)
{
	//初始化SYSTick产生一次中断的时间
	while(SysTick_Config(168000)!=0);//1ms产生一次中断
	
}

//计时程序 nTime*1ms
void Time_us(uint32_t nTime)
{ 
	if(TimingDelay == 0)
	{
		TimingDelay = nTime;
		GPIO_ToggleBits(GPIOF,GPIO_Pin_9);
	}

}
//在 SysTick 中断函数 SysTick_Handler()进行计数
void TimingDelay_Decrement(void)
{
	if (TimingDelay != 0x00)
	{ 
		TimingDelay--;
	}
}

3、注意事项

中断服务程序中修改的供其它程序检测的变量需要加volatile(即__IO)。

volatile(即__IO) 告诉编译器变量是随时可能发生变化的,每次使用它的时候必须从变量的地址中读取,因而编译器生成的可执行码会重新变量的地址读取数据。而如果没有使用__IO,编译器优化做法是,由于编译器发现两次从i中读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中,而不是重新从i里面读。

确定系统时钟配置的系统频率SYSCLK或HSECLK。

### 配置STM32标准库中的滴答定时器STM32标准库中,配置滴答定时器SysTick)通常涉及几个关键步骤。这些步骤确保能够正确初始化并使能SysTick定时器,从而实现精确的时间管理。 #### 初始化SystemCoreClock变量 `SystemCoreClock` 变量用于存储当前系统的时钟频率,在不同的设备型号下有不同的默认值。对于STM32F4系列而言,默认情况下 `SystemCoreClock` 被设定为168MHz[^1]: ```c #if defined(STM32F40_41xxx) uint32_t SystemCoreClock = 168000000; #endif /* STM32F40_41xxx */ ``` 此变量会在每次修改系统时钟配置后更新,因此开发者无需手动调整其值。 #### 设置SysTick定时器的重装载值 为了创建一个周期性的中断源来跟踪时间流逝,需要计算合适的重装载值。由于SysTick是一个24位递减计数器,最大可设范围是从0到16,777,215[^2]。假设希望每毫秒触发一次中断,则可以按照如下方式计算重载值: ```c // 假定SystemCoreClock=168MHz, 即168000000Hz #define SYSTICK_RELOAD_VALUE ((SystemCoreClock / 1000) - 1) // 减一因为当计数值达到零时会触发中断 ``` 这里通过将核心时钟频率除以期望的间隔次数(这里是千次),得到每个周期内的脉冲数量,并从中减去1作为实际加载至寄存器中的初始值。 #### 编写SysTick_Config()函数 接下来定义一个名为`SysTick_Config()` 的辅助函数来进行具体的硬件配置工作。该函数接受一个参数——所需的微秒延迟数目,并返回成功与否的状态码。内部实现了对NVIC (Nested Vectored Interrupt Controller)SysTick 控制/状态寄存器的操作[^4]: ```c ErrorStatus SysTick_Config(uint32_t ticks){ if((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk){return ERROR;} SysTick->LOAD = (uint32_t)(ticks & SysTick_LOAD_RELOAD_Msk); NVIC_SetPriority(SysTick_IRQn,(1<<__NVIC_PRIO_BITS)-1);/* lowest priority*/ SysTick->VAL = 0UL; /* Clear the counter value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | /* Enable interrupt */ SysTick_CTRL_ENABLE_Msk; /* Start counting */ return SUCCESS; } ``` 上述代码片段展示了如何利用宏定义简化寄存器访问过程以及怎样合理分配优先级给SysTick异常处理程序。 #### 实现全局变量uwTick及其增量逻辑 为了让应用程序更容易获取经过的时间戳信息,可以在项目中声明一个外部可见(`extern`)类型的无符号整型变量`uwTick` 。每当发生SysTick中断事件时,就在对应的ISR (Interrupt Service Routine) 中对该变量执行累加操作[^3]: ```c volatile uint32_t uwTick; void SysTick_Handler(void){ uwTick++; } ``` 这样做的好处是可以方便地基于这个不断增长的计数器开发各种依赖于绝对或相对时刻的功能模块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星顶照

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值