滴答定时器详解

STM32F1滴答定时器的讲解

1.概况

Systick定时器,是一个简单的定时器,对于CM3、CM4内核芯片,都有Systick定时器。Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。

2.使用介绍

本文介绍的滴答定时器主要是用于延时,下面我们通过两种方式来实现延时功能,一种是把滴答定时器当成普通的定时器来使用,另一种是模拟实时操作系统(RTOS),将滴答定时器作为心跳时钟,并采用时间摘取法来获得延时。
特别注意的是在使用过程中,两种方式对于LOAD寄存器写入的值会有区别,具体如下:
The RELOAD value can be any value in the range 0x00000001-0x00FFFFFF. A start value of 0 is possible, but has no effect because the SysTick exception request and COUNTFLAG are activated when counting from 1 to 0.
The RELOAD value is calculated according to its use:
l To generate a multi-shot timer with a period of N processor clock cycles, use a RELOAD
value of N-1. For example, if the SysTick interrupt is required every 100 clock pulses, set
RELOAD to 99.
l To deliver a single SysTick interrupt after a delay of N processor clock cycles, use a
RELOAD of value N. For example, if a SysTick interrupt is required after 400 clock
pulses, set RELOAD to 400.

3.相关寄存器

SysTick有四个寄存器,分别为CTRL(控制与状态寄存器)、LOAD(自动重装载值寄存器)、VAL(当前值寄存器)、CALIB(校准值寄存器)。最后一个校准值寄存器不常用,此处不做介绍,如想了解,可自行查看STM32F103的编程手册,其中4.5小节详细的介绍了相关寄存器及每一位代表的含义。

3.1 CTRL寄存器各位描述

位段 名称 类型 复位值 描述
16 COUNTFLAG R 0 如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1.如果读取该位,该位自动清零。
2 CLKSOURCE R/W 0 0=外部时钟源(STCLK) 1=内核时钟(FCLK)
1 TICKINT R/W 0 1=SysTick倒数到0时产生SysTick异常请求 0=数到0时无动作
0 ENABLE R/W 0 SysTick定时器的使能位

3.2 LOAD寄存器各位描述

位段 名称 类型 复位值 描述
23:0 RELOAD R/W 0 当倒数至0时,将被重新装载的值

3.3 VAL寄存器各位描述

位段 名称 类型 复位值 描述
23:0 CORRENT R/Wc 0 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在CTRL寄存器的COUNTFLAG位

需要注意的是,外部时钟源(STCLK)是HCLK(AHB总线时钟)的1/8,内核时钟(FCLK)是HCLK(AHB总线时钟)。

4.延时实现方式一

4.1滴答定时器初始化

//只需初始化一次即可
static u8  fac_us=0;	//us延时倍乘数
static u16 fac_ms=0;	//ms延时倍乘数

/*
函数功能:延时函数初始化
形参含义:SYSCLK 系统时钟
          SYSCLK单位为MHz
注    意:SysTick的时钟固定为HCLK时钟的1/8
*/
void delay_init(u8 SYSCLK)
{
	SysTick->CTRL&=~(1<<2); //详见《中文参考手册》P56 的备注2
	fac_us=SYSCLK/8;        //每个us需要的SysTick时钟数
	fac_ms=fac_us*1000;		  //每个ms需要的SysTick时钟数   
}

4.2微秒级延时函数

/*
函数功能:实现微秒级延时
形参含义:需要延时的微秒数
注    意:SysTick->LOAD为24位寄存器
         us<=(2^24)*8/SYSCLK
		 当SYSCLK=72M时,us<=1,864,135
*/
void delay_us(u32 us)
{		
	u32 time;
  
	SysTick->LOAD=us*fac_us;//设置重装载时间	  		 
	SysTick->VAL=0x00;  //清空计数器
	SysTick->CTRL=0x01; //开始倒数 	 
	do
	{
		time=SysTick->CTRL;//读取当前计数值
	}
	while((time&0x01)&&!(time&(1<<16)));//等待时间到达   
	SysTick->CTRL=0x00; //关闭计数器
	SysTick->VAL =0x00; //清空计数器	 
}

4.3毫秒级延时函数

/*
函数功能:实现毫秒级延时
形参含义:需要延时的毫秒数
注    意:SysTick->LOAD为24位寄存器
         ms<=(2^24)*8/SYSCLK/1000
		 当SYSCLK=72M时,ms<=1,864
*/
void delay_ms(u16 ms)
{	 		  	  
	u32 time;
  
	SysTick->LOAD=ms*fac_ms;//设置重装载时间		
	SysTick->VAL =0x00;  //清空计数器
	SysTick->CTRL=0x01 ; //开始倒数  
	do
	{
		time=SysTick->CTRL;//读取当前计数值
	}
	while((time&0x01)&&!(time&(1<<16)));//等待时间到达   
	SysTick->CTRL=0x00; //关闭计数器
	SysTick->VAL =0x00; //清空计数器	  	    
} 

5.延时实现方式二

5.1滴答定时器初始化

static u8  fac_us=0;//us延时倍乘数

/*
函数功能:滴答时钟初始化
形参含义:SYSCLK 系统时钟
          SYSCLK单位为MHz
注    意:SysTick的时钟固定为HCLK时钟的1/8
中断时间:time=1/SYSCLK/1,000,000*8*(load+1) s
*/
void SysTick_Init(u8 SYSCLK)
{
  SysTick->LOAD=89999;//设置重装载时间
	MY_NVIC_Init(1,1,SysTick_IRQn);//抢占优先级1,子优先级1
	fac_us=SYSCLK/8;//每个ms需要的SysTick时钟数
	SysTick->VAL=0; //清空计数器
	SysTick->CTRL|=3<<0;//开启计数器
}

5.2微秒级延时函数

/*
函数功能:实现微秒级延时
形参含义:需要延时的微秒数
注    意:延时时间一定不能超过10,000us
         延时时间范围和LOAD里的参数有关
         滴答时钟采用的是递减计数器
*/
void delay_us(u32 us)
{
	u32 reload=1+SysTick->LOAD;//读取重装载值 注意要加1
	u32 tick_us=us*fac_us;//计算所需的SysTick的时钟数 
	u32 new_us;//延时完成后VAL寄存器里的数值
  u32 old_us=SysTick->VAL;//读取当前的计数值
	
	if(old_us<tick_us)//情况一:延时过程中计数器会发生溢出的情况
	{
	  new_us=reload+old_us-tick_us;
		while(new_us<SysTick->VAL || SysTick->VAL<old_us);//等待计数完毕
	}
	else//情况二:延时过程中计数器不会发生溢出的情况
	{
    new_us=old_us-tick_us;	 
		while(new_us<SysTick->VAL);//等待计数完毕
	}
}

5.3毫秒级延时函数

//只需初始化一次即可
static u8  fac_us=0;	//us延时倍乘数
static u16 fac_ms=0;	//ms延时倍乘数

/*
函数功能:实现毫秒级延时
形参含义:需要延时的毫秒数
注    意:ms不应超过2^32
*/
void delay_ms(u32 ms)
{
	for(u32 i=0;i<ms;i++)
	{
	  delay_us(1000);
	}
}

5.4滴答定时器中断服务函数

u32 sys_ms = 0; //系统时间
u16 data_ms = 0;//系统指示灯工作时间	

/*
函数功能:滴答定时器中断服务函数
形参含义:无
注    意:10毫秒中断一次
*/
void SysTick_Handler(void)
{  
	data_ms += 10;//时间加10
	sys_ms += 10; //时间加10
	if(data_ms==500)//每隔500ms变换一次灯的状态
	{
	  data_ms=0;//时间重置,开启下一次计时
	}
}

你可能感兴趣的:(学习F1之旅)