STM32F4: Systick滴答定时器-延时函数讲解(五)

  1. Systick定时器基础知识讲解
  2. Systick相关寄存器库函数讲解
  3. delay延时函数讲解(Systick应用)
    频率定义:单位时间内完成周期性变化次数。
    (借鉴正点原子网课)
    (一)Systick定时器,是一个简单的定时器(最主要的),对于CM3,CM4内核芯片,都有Systick定时器。

Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。

(二)
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作(这也是为什么要特意开发出Systick定时器的缘由,如果此时用普通定时器在睡眠模式下会大大增加功耗 )。

SysTick定时器被捆绑在NVIC(中断优先级管理)中,用于产生SYSTICK异常。

Systick中断的优先级也可以设置。

(三)4个Systick寄存器
①CTRL SysTick 控制和状态寄存器 LOAD
STM32F4: Systick滴答定时器-延时函数讲解(五)_第1张图片
备注: TICKINT 中断位(1),M3外部时钟源72/8=9MHZ,M4外部时钟源是168/21=21MHZ

②SysTick 自动重装载除值寄存器
STM32F4: Systick滴答定时器-延时函数讲解(五)_第2张图片

③SysTick 当前值寄存器 CALIB
STM32F4: Systick滴答定时器-延时函数讲解(五)_第3张图片

(四)Systick库函数
STM32F4: Systick滴答定时器-延时函数讲解(五)_第4张图片

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;
  }
}
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ //两个中断中间有多少个ticks周期。
  if (ticks-1 > SysTick_LOAD_RELOAD_Msk)  return (1);   
//对tick值进行有效性分析,最后要写到24位的LOAD寄存器,不能大于24位寄存器2的24次方
      /* Reload value impossible */
   
 /* set reload register */                                                            
  SysTick->LOAD  = ticks - 1; //设置重装载寄存器值
/* set Priority for Cortex-M0 System Interrupts */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); //设置优先级
  SysTick->VAL   = 0;      //设置Value值为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 */
}
static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{ 
   TimingDelay = nTime;
   while(TimingDelay != 0);
}
void SysTdler(void)
{
    if (TimingDelay != 0x00) 
     { 
       TimingDelay--;
     }
}
 int main(void)
 {if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms
     {
     while (1);
     }
    while(1)
     { Delay(200);//2ms}
}

(四)用中断方式实现delay延时(举例)

static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{ 
   TimingDelay = nTime;
   while(TimingDelay != 0);
}
void SysTdler(void)   //每等待一毫秒产生一个中断
{
    if (TimingDelay != 0x00) 
     { 
       TimingDelay--;
     }
}
 int main(void)
 {if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms
     {
     while (1);
     }
    while(1)
     { Delay(200);//200ms}
}
//在Main中先设置好入口参数ticks的值,配置好初始化systick,进入Delay(200)循环,在这个循环体
//中每一次中断,Systick中断服务函数Systick_Handler自动减一,知道最后减到0,while结束循环,此延时函数也就结束了。

(五)delay_init函数介绍

//初始化延迟函数
//当使用 OS 的时候,此函数会初始化 OS 的时钟节拍
//SYSTICK 的时钟固定为 HCLK 时钟的 1/8
void delay_init()
{#if SYSTEM_SUPPORT_OS //如果需要支持 OS.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//选择外部时钟 HCLK/8
fac_us=SystemCoreClock/8000000; //为系统时钟的 1/8 
#if SYSTEM_SUPPORT_OS //如果需要支持 OS.
reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为 M 
reload*=1000000/delay_ostickspersec; //根据 delay_ostickspersec 设定溢出时间
//reload 为 24 位寄存器,最大值:16777216,在 168M 下,约合 0.7989s 左右
fac_ms=1000/delay_ostickspersec; //代表 OS 可以延时的最少单位 
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启 SYSTICK 中断
SysTick->LOAD=reload; //每 1/delay_ostickspersec 秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK 
#else
fac_ms=(u16)fac_us*1000; //非 OS 下,代表每个 ms 需要的 systick 时钟数 
#endif

该函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外部时
钟,如果需要支持操作系统(OS),只需要在 sys.h 里面,设置 SYSTEM_SUPPORT_OS 宏的值
为 1 即可,然后,该函数会根据 delay_ostickspersec 宏的设置,来配置 SysTick 的中断时间,并
开启 SysTick 中断。
可以看到,delay_init 函数使用了条件编译,来选择不同的初始化过程,如果不使用 OS 的
时候,只是设置一下 SysTick 的时钟源以及确定 fac_us 和 fac_ms 的值。

(六)Delay_us,Delay_xms,Delay_ms 的延时函数介绍

void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 				//时间加载,我们要延时n倍的us, 1us是一个fac_ua周期,所以总共要延时的周期值为二者相乘最后送到Load中。		 
	SysTick->VAL=0x00;        				//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开启使能位 开始倒数
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	//用来判断 systick 定时器是否还处于开启状态,然后在等待时间到达,也就是数到0的时候,此时第十六位设置为1
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器使能位
	SysTick->VAL =0X00;       				//清空计数器
}
void delay_xms(u16 nms)
{	 		  	  //跟上列同理
	u32 temp;	
	SysTick->LOAD=(u32)nms*fac_ms;	//
	SysTick->VAL =0x00;           			//
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;     
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	// 
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //
	SysTick->VAL =0X00;     		  		//	  	    
} 
//
void delay_ms(u16 nms)
{	 	 
	u8 repeat=nms/540;			//nms除以540后的整数值赋值给repeat,也就是倍数
	u16 remain=nms%540;  //nms除以540后余数值赋值给remain
	while(repeat)  //开始倍数循环  循环条件依次减一直到最后为零
	{
		delay_xms(540);  //延时一次540ms
		repeat--;
	}
	if(remain)delay_xms(remain); //延时n倍的540后,剩余的值在这里延时
} 

你可能感兴趣的:(STM32f4ZGT6,stm32,嵌入式,单片机)