STM32之SysTick定时器

1.SysTick简介:

     SysTick是系统滴答定时器,可以说是操作系统的的“心跳”,它被绑在NVIC中,用于产生SysTick异常(异常号:15)。一旦产生SysTick异常,就会产生滴答中断,这个滴答中断对操作系统尤其重要。例如:操作系统可以为多个任务分配不同数目的时间片,确保没有一个任务霸占系统,或者将每个定时器周期的某个时间范围赐于特定的任务等。操作系统提供的各种定时功能都与这个滴答定时器有关,因此需要一个定时器产生周期性的中断,而且最好让用户程序不能随意访问它的寄存器。以维持操作系统“心跳”的节律。

    而STM32内核包含了一个简单的定时器——SysTick,所有CM3芯片都带有这个定时器,该定时器的时钟源可以是内部时钟,也可以是外部时钟,在STM32中的SysTick以HCLK(AHB时钟)或HCLK/8作为运行时钟。

   SysTick定时器能产生中断,CM3为它专门开出一个异常类型,便且在向量表中有它的一席之地。 SysTick定时器除了能服务于操作系统外,还能用于其他目的,比如作为闹铃,用于测量时间。


2.SysTick工作分析

 SysTick是一个24位的定时器,即一次最多可以计数2的24次方个时钟脉冲,这个脉冲计数值被保存到当前计数值寄存器STK_VAL中,只能向下计数,每收到一个时钟脉冲STK_VAL的值就向下减1,直至0。当STK_VAL的值被减为0时,由硬件自动把重载寄存器STK_LOAD中保存的数据加载到STK_VAL,重新向下计数。当STK_VAL的值被计数至0,就可以在中断服务函数中处理定时事件了。






下面写了个跑马灯的程序来体验一下SysTick定时器的作用。看代码:

主函数:main.c

#include "systick.h"
#include "led.h"

int main(void)
{  
	LED_Init();
  SysTick_Init();	  //配置SysTick为1ms中断一次
	while(1)
	{
             LED1_OFF;
             Delay_ms(500);     //500 * 1ms=500ms
	     LED1_ON;
	     LED2_OFF;
	     Delay_ms(500);     //500 * 1ms=500ms
	     LED2_ON;
	     LED3_OFF;
	     Delay_ms(500);     //500 * 1ms=500ms
	     LED3_ON;
  }
	
}

SysTick初始化函数:systick.c

#include "systick.h"
__IO uint32_t TimingDelay;
void TimingDelay_Decrement(void)
{
    if(TimingDelay !=0x00)
     {
       TimingDelay--;
     }
}
void SysTick_Init(void)
{
    if(SysTick_Config(SystemCoreClock / 1000))//
     {
      /*Capture error */
        while(1);
     }
	  /*关闭滴答定时器*/
	SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}
void Delay_ms(__IO uint32_t nTime)
{
    TimingDelay=nTime;
	  /* 使能滴答定时器*/
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
    while(TimingDelay !=0);
}

*****************************************************************************************************************************************************************************************************

注意:这里最重要的就是SysTick_Config()配置函数了,追踪这个函数,发现它是在core_cm3.h文件中,

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* 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 (0);                                                  /* Function successful */
}
(1)这个函数都有英文注释,通过看这个注释就能知道函数的功能,这个函数启动了SysTick,便把它配置为计数至0时引起中断输入的参数ticks为两个中断之间的脉冲数,即相隔ticks个时钟周期会引起一次中断;配置Systick成功时返回0,出错时返回1。

(2)从这个函数可以知道,ticks也是有上限值的,具体多大,可以追这个SysTick_LOAD_RELOAD_Msk宏,#define SysTick_LOAD_RELOAD_Msk(0xFFFFFFul << SysTick_LOAD_RELOAD_Pos),通过这个宏我们知道ticks的最大值不能超过十六进制0xffffff,也就是十进制16777215,一般用到中断,我们都要进行NVIC配置,而这个代码用到了中断,为什么外部没有进行NVIC配置呢?仔细观察,你会发现SysTick_Config()函数中已经调用了NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1)函数,这就是答案。

(3)SysTick_Config()函数中的注释没有告诉我们SysTick的时钟是AHB时钟还是AHB/8,这个很关键,注意看,这个函数向STK_CTRL寄存器写入了SysTick的控制参数,在这里我们就知道配置为了AHB时钟,当然这里还要参考STM32的datasheet,查看STK_CTRL寄存器介绍,一切就明白了。

(4)本例子采用的是AHB时钟,其频率被配置为72MHz.调用函数时,把ticks赋值为ticks=SystemCoreClock/1000=7200,表示7200个时钟周期中断一次;定时j计算公式为:T=ticks x (1/f),T为要定时的总时间,ticks为输入参数,1/f为SysTick使用的时钟源的时钟周期,f为该时钟源的时钟频率,当时钟源确定后就为一个常数。由于时钟源是AHB,AHB又默认时钟为72MHz ,所以我写的程序中1/f=1/72us,最终定时总时间T=7200 x (1/72)us=1ms,还要注意一点,由于SysTick定时器是24位的,故最大定时周期不能超过2的24次方个。

LED初始化函数:led.c

#include "led.h"

void LED_Init()	 //LED初始化函数
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
	
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	GPIO_Init(GPIOD,&GPIO_InitStructure);
		
}
中断服务函数:stm32f10x_it.c

void SysTick_Handler(void)
{
	TimingDelay_Decrement();
}
中断服务函数中的TimingDelay_Decrement()是我自己定义的,在systick.c文件中定义的。




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值