STM32 Systick定时器延时


Systick定时器延时

一、系统定时器


1. 目的

Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。

2. 简介

SysTick 叫做系统滴答时钟、系统定时器,属于 Cortex-M4内核中的一个外设(外围设备),也是属于NVIC的一部分,并且是24bit向下递减的计数器。

==最大计数:== 2^24-1 (向下计数到0,然后触发中断)

3. SysTick寄存器

序号 寄存器 名称 描述
1 CTRL Systick控制和状态寄存器 使能Systick定时器并设置时钟源
2 LOAD Systick自动重装载寄存器 当倒数至零时,将被重装载值
3 VAL Systick当前值寄存器 读取时返回当前倒数值,写它则使之清零
4 CALB Systick校准值寄存器 不常用

(1)Systick控制和状态寄存器

Sys-Tick.png

==外部时钟==是 HCLK(AHB总线时钟) 的1/8 (stm32f401 是 168/8=21M)
==内核时钟==是 HCLK时钟 (stm32f401 是 84M)

(2)Systick自动重装载寄存器

Sys-Tick.png

(3)Systick当前值寄存器

Sys-Tick.png

(4)Systick校准值寄存器

Sys-Tick.png

4. 计时原理

time = 中断次数*一次中断时间
重装载次数为n,一次中断时间为t=1/SYSCLK,中断时间为T;
T = n * t


二、精准延时函数

1. 固件库函数延时

int n=0;//全局变量
void SysTick_Init(void)
{ 
  	//uint32_t SystemCoreClock = 84000000;
  	//SystemFrequency / 1000     1ms    中断一次
  	//SystemFrequency / 100000   10us   中断一次
  	//SystemFrequency / 1000000  1us    中断一次
    if (SysTick_Config(SystemCoreClock/1000000))     /*让系统中断一次耗时1us*/
    {
        while (1);
    }
}
void delay_us(__IO u32 nTime)
{
    n =nTime;
    while(n>0);
}
delay_ms(__IO u32 nTime)
{
    n =nTime*1000;
    while(n>0);
}
void SysTick_Handler(void)
{
if(n!=0x00)
    {
        n--;
    }
}

2. 寄存器延时

寄存器延时比固件库函数写的更精简,推荐使用这种延时。

#define     PLL_m       8

/*----------------Systick微秒级延时----------------*/
void delay_us(u32 nus)
{
 u32 temp;
 
 SysTick->LOAD = SystemCoreClock/PLL_m/1000000*nus;//设置重装载值 = 84000000/8/1000000 * n    (1us中断一次)
 
 SysTick->VAL=0X00;//清空计数器
 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
 do
 {
  temp=SysTick->CTRL;//读取当前倒计数值
 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
 
    SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

/*----------------Systick毫秒级延时----------------*/
void delay_ms(u16 nms)
{
 u32 temp;
 SysTick->LOAD = SystemCoreClock/PLL_m/1000*nms;//设置重装载值 = 84000000/8/1000 * n  (1ms中断一次)
 SysTick->VAL=0X00;//清空计数器
 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
 do
 {
  temp=SysTick->CTRL;//读取当前倒计数值
 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

3. 软延时

在延时精度要求低的情况下建议采用软延时,减少中断次数。
/*----------------软微秒级延时----------------*/
void Delay_us(uint32_t Delay_us)
{    
  volatile unsigned int num;
  volatile unsigned int t;
 
  
  for (num = 0; num < Delay_us; num++)
  {
    t = 11;
    while (t != 0)
    {
      t--;
    }
  }
}
/*----------------软毫秒级延时----------------*/
void Delay_ms(uint16_t Delay_ms)
{    
  volatile unsigned int num;
  for (num = 0; num < Delay_ms; num++)
  {
    Delay_us(1000);
  }
}

/*----------------软I2C延时----------------*/
void I2C_Delay(void)
{
	uint8_t i;

	for (i = 0; i < 100; i++);
}

三、编程总结

  1. 注意systick的时钟,首先需要先设置systick时钟源。
  2. 接着设置重装载寄存器的值。
  3. 清除当前数值寄存器的值。
  4. 配置控制与状态寄存器。
  5. 在main函数中循环调用延时函数实现灯闪烁。
  6. systick延时在之后起着重要作用,许多程序涉及到延时函数的调用,因此写好一个精准的延时函数必不可少!

文章作者: 机械22级肖文林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 机械22级肖文林 !
评论
  目录