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

STM32的Systick滴答定时器及延时函数编写

程序员文章站 2024-02-24 09:28:31
...

一、Systick滴答定时器是什么?

    Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器计到时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作

  定时器既是在规定时间之后执行某个操作。

    Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用SystickUCOS心跳时钟。

------------------------------------------------------------------------------------------------------------------------------------------------------

二、Systick一般用来做延时,精确延时。

一共4个Systick寄存器

    CTRL             SysTick 控制和状态寄存器 

    LOAD             SysTick 自动重装载初值寄存器 

    VAL              SysTick 当前值寄存器 

    CALIB            SysTick 校准值寄存器

------------------------------------------------------------------------------------------------------------------------------------------------------

三、systick定时器原理

这个定时器是设置一个初值,然后这个初值减数到0,就是定时完成,完成之后可以产生中断,也可以不使用中断。

STM32的Systick滴答定时器及延时函数编写

第0位是使能位,可以使能或者使能定时器

第1位是使能中断位,减数结束之后是否产生中断。

第2位是时钟选择位,可以选择外部的或者内部时钟作为时钟源。

第16位是标志位,减数到0之后该位被置位1,读取过后自动清清零。

------------------------------------------------------------------------------------------------------------------------------------------------------

四、uSysTick 重装载数值寄存器-LOAD

STM32的Systick滴答定时器及延时函数编写

当当前值寄存器减数到0,自动会将把这个RELOAD的值赋给当前值寄存器。

if(VAL == 0)

    VAL = RELOAD

------------------------------------------------------------------------------------------------------------------------------------------------------

五、SysTick 当前值寄存器- VAL

STM32的Systick滴答定时器及延时函数编写

VAL就是从初值(RELOAD)一直减一,倒数到0的时候,重新将初值(RELOAD)赋给VAL。

------------------------------------------------------------------------------------------------------------------------------------------------------

六、滴答定时器的实现

对于STM32,外部时钟源是HCLK(AHB总线时钟)的1/8内核时钟是HCLK时钟

1、选择时钟源

    SysTick_CLKSourceConfig();//选择时钟源 misc.c文件中

STM32的Systick滴答定时器及延时函数编写

    SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断 core_cm4.h文件中

STM32的Systick滴答定时器及延时函数编写

2、编写延时函数

3、设置中断优先级分组

    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);

    一般使用中断都需要在最开始对我们的优先级进行分组,分好之后再进行优先级的设置。

    尽量不要在同一个程序里面频繁的改变分组,频繁切换分组可能会使程序出现不可预料错误。

------------------------------------------------------------------------------------------------------------------------------------------------------

七、用中断的方式实现delay延时
Systick中断服务函数:void SysTick_Handler(void);

STM32的Systick滴答定时器及延时函数编写

-----------------------------------------------------------------------------------------------------------------

注意:

  uCortex-M系统中,Systick代码可以通用。

  如果使用中发现延时不一致,问题一般都是因为不同内核时钟不一样而已。修改ticks值即可。

------------------------------------------------------------------------------------------------------------------------------------------------------

参考代码如下:

void init_delay(void)
{
    /*我们外部晶振为8MHz,然后倍频到168M,那么Systick时钟即为21M,也就是Systick的计数器
    VAL每减1就代表过了1/21us*/

    //1.选择时钟源(选择外部时钟)
    //外部时钟要/8,内部始终不用
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
}

//2.编写延时函数
//最大延时不超过798.915ms,即(2^24)/21/1000
void delay_us(u32 nus)
{
    u32 temp = 0;

    //1、实现1us*nus的延时
    //21外是外部时钟频率,如果选择内部时钟就是168M/8
    SysTick->LOAD = 21*nus;//设置自动装载值为21(1us)
    SysTick->VAL = 0x00;//设置当前初值为0
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开启(使能)计数:使能SysTick定时器

    do
    {
        //读取控制寄存器
        temp = SysTick->CTRL;
    }while(!(temp & (1<<16)));//等待计数时间到达(位16)

    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭(失能)计数
    SysTick->VAL = 0x00;//再设置当前初值为0,重置VAL 
}

void delay_ms(u32 nms)
{
    u32 temp = 0;

    //1、实现1us*nus的延时
    SysTick->LOAD = 21000*nms;//设置自动装载值为21(1us)
    SysTick->VAL = 0x00;//设置当前初值为0
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开启(使能)计数

    do
    {
        //读取控制寄存器
        temp = SysTick->CTRL;
    }while(!(temp & (1<<16)));

    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭(失能)计数
    SysTick->VAL = 0x00;//再设置当前初值为0 
}

void delay_s(u32 s)
{
    while(s--)
    {
        delay_ms(500);
        delay_ms(500);
    }
}