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

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

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

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

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

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

在这里插入图片描述

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

有4个寄存器控制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)
在这里插入图片描述

具体代码:

//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/fac_us@fac_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;       				//清空计数器 
}

在这里插入图片描述
注释已经在代码中了,十分详细。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值