SysTick延时

相关代码:

void delay_us(u32 uS) {
    SysTick->LOAD=72*uS;                         //重装计数初值(当主频是72MHz,72次为1微秒)
    SysTick->VAL=0x00;                               //清空定时器的计数器
    SysTick->CTRL=0x05;                             //选择时钟源HCLK,打开定时器
    while(!(SysTick->CTRL&0x10000));     //等待计数到0
    SysTick->CTRL=0x04;                             //关闭定时器
    //这个中断是由硬件自动触发的,不受软件控制
    //因此,即使没有显式地设置打开总中断,SysTick 定时器的中断仍然会生效,因为它是由硬件触发的。
}
void delay_ms(u16 ms){ //mS毫秒级延时程序(参考值即是延时数,最大值65535)                 
    while( ms-- != 0){
        delay_us(1000); //调用1000微秒的延时
    }
}
void delay_s(u16 s){ //S秒级延时程序(参考值即是延时数,最大值65535)                 
    while( s-- != 0){
        delay_ms(1000); //调用1000毫秒的延时
    }
}

Systick是Cortex内核当中,中断寄存器的一部分,因此相关的函数以及寄存器介绍在Cortex-M3编程手册内可见,固件编程手册函数仅供参考。

SysTick延时-1

由参考手册可知,SysTick寄存器由四个寄存器组成。我们只需要使用其中的3个寄存器:

STK_CTRL(控制及状态寄存器):

当CLKSOURCE为0时,则选择外部时钟源,即(stm32f103c8t6最小系统板外置晶振为8M,通过PLL倍频到72MHz)72MHz的8分频(AHB/8),在load装载初值时,计数72/8=9次即为1us。

当CLKSOURCE为1时,则选择内核时钟(72M),计数72次即为1us。

SysTick延时-2

重装载数值寄存器(RELOAD):

SysTick延时-3

当前数字寄存器(VAL):(用于中断)

SysTick延时-4

校准数值寄存器(CALIB):

SysTick延时-5

利用中断来实现对滴答定时器的配置:

  • 滴答定时器是一个24位的倒计数定时器,当计数到0时,将从RELOAD寄存器中自动装载初值。
  • 只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
  • 设置的定时时间 = RELOAD寄存器值 x 1/72M
  • 例如RELOAD = 72000,则定时时间 = 72000 x 1/72M = 1ms

1、设置RELOAD需要通过SysTick_Config来设置:

  • SysTick_Config(72000000/1000);

2、当定时时间到了之后,滴答定时器会产生中断

  • 使用中断就需要打开总中断的开关,因此需要到core_cm3中找到控制总中断的函数__set_PRIMASK(0);使能总中断需要设置为0。

3、使用中断还需要对中断进行分组

  • STM32F103内部有16个内核中断和60个可屏蔽(关闭)中断,具有16个级别的可编程的中断优先级
  • 中断的分组需要用到NVIC-内嵌向量中断控制器
  • 该控制器将中断一共分为五个组,分为组0-4

SysTick延时-6

在misc中找到该函数:NVIC_PriorityGroupConfig();(NVIC优先级分组配置,一般参数填NVIC_PriorityGroup_2)

4、在进入滴答定时器完成计时后进入中断,我们还需要编写处理中断的中断处理函数。

  • 该函数可在STM32的启动文件当中找到:SysTick_Handler(void);
  • 当定时的时间到了之后,就会进入到该中断函数内。

滴答定时器的中断没有设置优先级,是因为滴答定时器的中断是在系统内核当中的,在系统内已经设置好了。

在SysTick_Config();函数当中已经通过配置寄存器设置了滴答定时器的中断优先级(1左移4位等于15)。

#include "SysTick.h"
u32 DelayTimer;

void SysTick_Init(void) {
    //定时器装载初始值,装载72000即定时1ms,该函数位于core_cm3
    SysTick_Config(72000000/1000);
    //定时器会产生中断,所以需要打开总中断开关,该函数位于core_cm3
    __set_PRIMASK(0);
    //凡是使用中断都需要对中断设置分组,SysTick属于内核中断
    //设置中断分组需要设置NVIC,一般设置为组2,函数位于misc
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
}

void SysTickDelayMs(u32 nms) {
    DelayTimer = nms;
    while(DelayTimer); //执行空语句
}   

void SysTick_Handler(void) {
    if(DelayTimer) DelayTimer--;
}