STM32之SysTick定时器

SysTick-------操作系统的心跳

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

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

   SysTick定时器能产生中断,CM3为它专门开出一个异常类型,便且在向量表中有它的一席之地。 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,就可以在中断服务函数中处理定时事件了。

时间单位换算:1s=1000ms=10^6 us=10^9

扫描二维码关注公众号,回复: 22281 查看本文章
下面我们来看程序:

/*
* 函数名 :main
* 描述   :主函数
* 输入   :
* 输出   :
*/

int main(void)
{
	
    /*LED 端口初始化 */
	init_led_gpio();
	//system_init();

	/*配置systick 为10us中断一次*/
	SysTick_Init();
	
	for(;;)
  {
  
   turn_led(LED1,ON);
	 Delay_us(50000);
	 turn_led(LED1,OFF);
	 
	 turn_led(LED2,ON);
	 Delay_us(50000);
	 turn_led(LED2,OFF);
	 
	 turn_led(LED3,ON);
	 Delay_us(50000);
	 turn_led(LED3,OFF);
	
  }
} 
在main函数中,Systick_Init( )和Delay_us( )这两个函数比较陌生,他们的功能分别是配置 Systick定时器和进行精确延时。
整个main函数的流程就是初始化LED及 Systick定时器之后,就进入死循环,轮流点亮LED1,LED2,LED3,点亮的时间为精确的
500ms。
接下来便是配置并启动 Systick
Systick_Init()这个函数,它是用户在 Systick.c这个文件中实现的,其功能是启动系统滴答定时器 Systick,并将 Systick配置为10us中断一次。
#include "SysTick.h"
#include "stm32f10x_it.h"
#include "core_cm3.h"
#include "system_stm32f10x.h"
static __IO u32 TimingDelay;
/*
* 函数名 :SysTick_Init
* 描述   :启动系统滴答定时器 SYSTICK
* 输入   :
* 输出   :
* 调用   :外部调用
*/

void SysTick_Init(void)
{
   /* systemFrequency /1000  1ms中断
	  * systemFrequency /100000  10us中断
	  * systemFrequency /1000000  1us中断
	  */
	 //if (SysTick_Config(SystemFrenquency /100000)) ST3.0.0库版本
	   if (SysTick_Config(SystemCoreClock /100000)) // ST3.5.0库版本
		 {
			 /* Capture error */
			 while(1);
		 }
		 
		 //关闭滴答定时器
		 SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
	 }
	 
	 
	 /*
	  * 函数名:Delay_us
	  * 描述  :us 延时程序,10us 为一个单位
	  * 输入  :
	  * 输入  :
	  * 调用  : Delay_us(1) 则实现的延时为1*10us = 10us
	  */
	  
	 
	 void Delay_us(__IO u32 nTime)
	 {
		 TimingDelay = nTime;
		 //使能滴答定时器1
		 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
		 while(TimingDelay !=0);
	 }
	 
	 
	 /*
	  * 函数名:TimingDelay_Decerment
	  * 描述  : 获取节拍程序
	  * 输入  :
	  * 输入  :
	  * 调用  : 在SysTick中断函数 SysTick_Handler()调用
	  */
	 
	 
	void TimingDelay_Decrement(void)
 {
	 if (TimingDelay != 0x00)
	 {
		 TimingDelay--;
	 }
 }  

Sys tick_Init() 函数实际上只调用了Systick_Config()函数,它是属于内核层的Cortex_M3通用函数,位于Core_cm3.h文件中,若调用 Systick_Config()配置Systick不成功,则进入死循环,初始化 Systick成功后,先关闭定时器,需要的时候再开启。

使能   关闭定时器

// 使能滴答定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //(或运算)
//使能滴答定时器
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//(与运算)

接下来到编写中断服务程序啦
让我们回到main函数中,我们使LED工作在一个无限循环中,在LED的开与关之间调用了Delay_us函数
/*
	  * 函数名:Delay_us
	  * 描述  :us 延时程序,10us 为一个单位
	  * 输入  :
	  * 输入  :
	  * 调用  : Delay_us(1) 则实现的延时为1*10us = 10us
	  */
	  
	 
	 void Delay_us(__IO u32 nTime)
	 {
		 TimingDelay = nTime;
		 //使能滴答定时器1
		 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
		 while(TimingDelay !=0);
	 }

一旦我们调用了Delay_us()函数,SysTick定时器就被开启,按照设定好的定时周期递减技术,当Systick的计数寄存器的值减为0时,就进入中断函数,当中断函数执行完毕之后重新计时,如此循环,除非它被关闭。
使用   Systick 测量时间的功能
稍微改变一下用法,我们就可以利用systick进行时间测量,这个是下一篇博客要写的内容啦(手动比心大笑



猜你喜欢

转载自blog.csdn.net/panrenqiu/article/details/79933387