欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32-滴答定时器(SysTick)用作延时函数的时基

程序员文章站 2024-02-24 10:24:34
...

本文基于STM32F407ZGT6
—————————————

滴答定时器(SysTick)的作用:

  • 1、作为操作系统时基
  • 2、作为精确延时函数时基(delay函数)

滴答定时器是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时器初值,只要不把它在 SysTick 控制寄存器以及状态寄存器中的使能位清零,就将永久不息。

  • Cortex‐M3/4 在内核水平上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。
  • 编号为 1-15 的对应系统异常,大于等于 16 的则全是外部中断。
  • 有 3 个固定优先级的系统异常:复位,NMI 以及硬 fault,它们的优先级是不可编程的,它们的优先级号是负数,从而高于所有其它异常。
  • 其它异常的优先级则都是可编程的(但不能编程为负数)做成芯片后,支持的中断源数目常常不到 240
    个,并且优先级的位数也由芯片厂商最终决定。但是16个异常一般都是拥有的,这16个异常都有共同的特性,比如它们的位操作是一样的,这增加了同一内核不同芯片之间代码的可移植性。

STM32-滴答定时器(SysTick)用作延时函数的时基

SysTick寄存器:(可通过M3/4权威指南查看
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。
在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。

有4个寄存器控制SysTick定时器:
STM32-滴答定时器(SysTick)用作延时函数的时基
STM32-滴答定时器(SysTick)用作延时函数的时基

库函数里面的结构体:

typedef struct
{
  __IO uint32_t CTRL;                    /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IO uint32_t LOAD;                    /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register       */
  __IO uint32_t VAL;                     /*!< Offset: 0x008 (R/W)  SysTick Current Value Register      */
  __I  uint32_t CALIB;                   /*!< Offset: 0x00C (R/ )  SysTick Calibration Register        */
} SysTick_Type;

看后面的注释知道四个结构体成员对应上面四个寄存器。

SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间(delay延时函数)等。
要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。

是个定时器都需要时钟来源,从时钟树来看,SysTick定时器的时钟是AHB/8(也就是HCLK/8)。如果我们外部晶振为 8M,然后倍频到 168M,那么 SysTick 的时钟即为 21Mhz。也就是 SysTick 的计数器 VAL (定时器的CURRENT寄存器)每减 1,就代表时间过了 1/21us ——在21Mhz的频率跳动时,每跳1次所用的时间,1/21us称它为时基:1/(21x10^6hz)=1/21us。(这就是为什么后面程序里面fac_us=SYSCLK/8的原因,在这里SYSCLK=168,所以fac_us=21)
STM32-滴答定时器(SysTick)用作延时函数的时基

具体代码:

//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
	/*定义SysTick的时钟来源,可以是HCLK或者是HCLK/8*/
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	
	/*SYSCLK是传进来的参数,这里是STM32F4,所以SYSCLK是168*/
	/*HCLK/8定时器时基为1/21us,所以1us跳21次,这就是SYSCLK/8的原因*/
	fac_us=SYSCLK/8;					 	//fac_us其实就是定时1us了,这里是一个值21
	fac_ms=(u16)fac_us*1000;				//代表每个ms需要的systick时钟数   
}			

那么我们看看us的延时函数:

//延时nus
//nus为要延时的us数.	
//注意:nus的值,不要大于798915us(最大值即2^24/aaa@qq.com_us=21)
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 				//时间加载fac_us=21,每个us跳21次	  		 
	SysTick->VAL=0x00;        				//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //SysTick定时器使能,开始倒数,SysTick_CTRL_ENABLE_Msk=1 	 
	do
	{
		/*判断SysTick的控制及状态寄存器(CTRL)第16位是否置1(置1代表倒计数结束)
		temp&0x01这个语句是判断SysTick是否已经使能(其实可以省略这个语句)
		!(temp&(1<<16)判断CTRL寄存器16位是否置1,置1取反后为0则跳出循环
		*/
		temp=SysTick->CTRL;                  //把CTRL寄存器的值赋给temp
	}while((temp&0x01)&&!(temp&(1<<16)));	//等待时间到达  
	
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //ysTick定时器使能位清零,关闭计数器
	SysTick->VAL =0X00;       				//清空计数器 
}

STM32-滴答定时器(SysTick)用作延时函数的时基
注释已经在代码中了,十分详细。