stm32的systick原理与应用

/* SysTick滴答定时器
一、功能
SysTick定时器是一个简单的定时器,CM3\CM4内核芯片都具备此定时器。SysTick定时器常用来做延时,采用实时系统时则用来做系统时钟。无论用作延时还是用作系统心跳时钟,不需要太复杂的功能,SysTick即可胜任。
二、实现原理
SysTick定时器是一个24位的倒计数,当倒计数为0时,将从RELOAD寄存器中取值作为定时器的初始值,同时可以选择在这个时候产生中断(异常号:15)。
例如从RELOAD的值为999,那么当倒计数为0时,就会从复位为999继续倒计数。
        只要不把它在SysTick控制及状态寄存器中的使能位清楚,就永不停息,即使在睡眠模式下也能继续工作。
三、SysTick寄存器(在 core_cm3.h 有定义,凡是 M3 内核的单片机都是一样的) */
#define SysTick             ((SysTick_Type *)       SysTick_BASE)
#define SysTick_BASE        (SCS_BASE +  0x0010)
#define SCS_BASE            (0xE000E000)
typedef struct
{
    __IO uint32_t CTRL;  // 控制及状态寄存器
    __IO uint32_t LOAD;   // 重装载数值寄存器
    __IO uint32_t VAL; // 当前计数数值寄存器
    __I  uint32_t CALIB;  // 校准寄存器
} SysTick_Type;
/*
SysTick->CTRL: (可通过 SysTick_CLKSourceConfig() 函数设置)
COUNTFLAG(16)R: 计数标志位
当SysTick数到0,则该位被硬件置 1,当读取该位时,将被硬件清零

CLKSOURCE(2)R/W: 时钟源设置
1 = 外部时钟源(STCLK) (AHB总线时钟的1/8(HCLK/8))
0 = 内核时钟(FCLK)  (AHB总线时钟的频率(HCLK))

TICKINT(1)R/W: 中断使能位
1 = SysTick 倒数到0时产生 SysTick 异常请求
0 = 数到 0 时无动作

ENABLE(0)R/W: SysTick 定时器使能位
(当中断被使能后,需要关注 void SysTick_Handler(void) 函数)
SysTick_Type->LOAD: (SysTick_Config() 函数会设置该寄存器)

RELOAD(23:0)R/W: 重装载数值寄存器
当SysTick数到0,将被重装载的值

SysTick_Type->VAL: (SysTick_Config() 函数会设置该寄存器)
CURRENT(23:0)R/Wc: 当前计数数值寄存器
读取时返回当前倒计数的值,写它则使之清零,同时还会清除在 SysTick 控制及状态寄存器中的 COUNTFLAG 标志。

四、库函数分析
misc.c
---------------------------------------------------------------------------------- */
#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
((SOURCE) == SysTick_CLKSource_HCLK_Div8))
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
    /* Check the parameters */
    assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
    if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
    {
        SysTick->CTRL |= SysTick_CLKSource_HCLK; // 设置 CLKSOURCE 为 1
    }
    else
    {
        SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;      // 设置 CLKSOURCE 为 0
    }
}

core_cm3.c
----------------------------------------------------------------------------------
#define SysTick_LOAD_RELOAD_Pos             0
#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos)
typedef enum IRQn
{
//...
    SysTick_IRQn                = -1,
//...
} IRQn_Type;
#define __NVIC_PRIO_BITS          4
#define SysTick_CTRL_CLKSOURCE_Pos          2
#define SysTick_CTRL_CLKSOURCE_Msk         (1ul << SysTick_CTRL_CLKSOURCE_Pos)

#define SysTick_CTRL_TICKINT_Pos            1
#define SysTick_CTRL_TICKINT_Msk           (1ul << SysTick_CTRL_TICKINT_Pos)

#define SysTick_CTRL_ENABLE_Pos             0
#define SysTick_CTRL_ENABLE_Msk            (1ul << SysTick_CTRL_ENABLE_Pos)

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
    if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
    // 设置计数值为 ticks - 1
    // 原因1:视频说是执行这些代码需要时间,所以减少一个节拍
    // 原因2:我认为是因为 SysTick 的倒计数到 0,例如设置 1000 ,那么范围就应该是 999 ~ 0。
    SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
    // 设置中断优先级
    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
    SysTick->VAL   = 0;
    // 设置时钟源为外部时钟源,同时开启中断、并使能 SysTick 定时器
    SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                     SysTick_CTRL_TICKINT_Msk   |
                     SysTick_CTRL_ENABLE_Msk;
    return (0);
}
/* 五、延时应用
1、中断方式 */
static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{
    TimingDelay = nTime;
    while(TimingDelay != 0);
}
/* 中断服务函数 */
void SysTick_Handler(void)
{
    if (TimingDelay != 0x00)
    {
        TimingDelay--;
    }
}
int main(void)
{
// ...
    if (SysTick_Config(SystemCoreClock / 1000)) // 注意,这里systick时钟为HCLK,中断时间间隔1ms
    {
        while (1);
    }
    while(1)
    {
        Delay(200);//2ms
// ...
    }
}
/* SysTick_Config(SystemCoreClock / 1000): (原代码这里假设是采用时钟源为 HCLK)
这里设置的是 72000000Hz / 1000 = 72000 ticks,也就是说 SysTick 从 (72000-1) 开始倒数。
每倒数完 72000 个节拍就触发一次中断。
一个节拍的时间为:72000000 / 72000 = 1000us == 1ms
SysTick_Config((SystemCoreClock / 8000000) * 1000 * 1):
SysTick_Config() 会设置时钟源为 HCLK/8 所以实际应用中不能按照上述代码的参数。
SystemCoreClock / 8000000: 1us 的节拍数
1us的节拍数 * 1000: 则为 1ms 的节拍数
1ms 的节拍数 * 1: 设置 1ms 一个SysTick中断,即从 ((SystemCoreClock / 8000000) * 1000 * 1) - 1 开始倒数。
2、轮询方式 */
static u8  fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数
void delay_init()
{
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟  HCLK/8
    fac_us = SystemCoreClock/8000000;         // 为系统时钟的1/8  1us = 72000000 / 8000000 =  9 个节拍
    fac_ms = (u16)fac_us*1000; // 1ms 需要 9 * 1000 = 9000 个节拍
}
//延时 nus 微秒
void delay_us(u32 nus)
{
    u32 temp;
    SysTick->LOAD=nus*fac_us;  //时间加载
    SysTick->VAL=0x00;          //清空计数器
    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;                //开始倒数
    do
    {
        temp=SysTick->CTRL;
    }
    while((temp&0x01)&&!(temp&(1<<16)));  //等待时间到达
    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;//关闭计数器
    SysTick->VAL =0X00;                     //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{
    u32 temp;
    SysTick->LOAD=(u32)nms*fac_ms;   //时间加载(SysTick->LOAD为24bit)
    SysTick->VAL =0x00;                       //清空计数器
    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //开始倒数
    do
    {
        temp=SysTick->CTRL;
        //等待时间到达,这里使用了一个小技巧,通过(temp&0x01)检查 SysTick 的使能位,避免 Systick 定时器被关闭而导致无限循环
    }
    while((temp&0x01)&&!(temp&(1<<16)));
    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
    SysTick->VAL =0X00;                      //清空计数器
}

SYSTick 定时器
CM3 内核的处理器,内部包含了一个 SysTick 定时器,(SysTick 的时钟源自HCLK的8分频,8个系统时钟周期systick跳一个,即8*1/72M=1/9 us)SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
利用 STM32 的内部 SysTick 来实现延时的,这样既不占用中断,也不占用系统定时器。因为在 ucos 下 systic 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者delay_ms 的延时,就必须想点办法了,这里我们利用的是时钟摘取法。以 delay_us 为例,比如delay_us (50),在刚进入 delay_us 的时候先计算好这段延时需要等待的 systick 计数次数,这里为 50*9 (假设系统时钟为 72Mhz,那么 systick 每增加 1,就是 1/9us) ,然后我们就一直统计systick的计数变化,直到这个值变化了50*9,一旦检测到变化达到或者超过这个值,就说明延时50us时间到了。———实质上就是不改变systick基本单位时长,以基本单位时长为基本元做多次到达摘取。

原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/9738099.html

时间: 2024-10-08 00:34:29

stm32的systick原理与应用的相关文章

stm32之Systick(系统时钟)

Systick的两大作用: 1.可以产生精确延时: 2.可以提供给操作系统一个单独的心跳(时钟)节拍: 通常实现Delay(N)函数的方法为: for(i=0;i<x;i++) ; 对于STM32系统微处理器来说,执行一条指令只有几十ns(纳秒),进入for循环,要实现N毫秒的x值非常大:而由于系统频率的宽广,很难计算出延时N毫秒的精确值:针对STM32微处理器,需要重新设计一个新的方法去实现该功能,以实现在程序中使用Delay(N): cortex的内核中包含一个SysTick时钟,SysTi

STM32之SysTick(系统定时器)

SysTick定时器是被捆绑在NVIC中的,用于产生SysTick异常(异常号是15).(同样,玩过51单片机的都知道定时器的作用了) 在STM32在内核部分是包含了一个简单的定时器–SysTick timer.因为在所有的Cortex-M3芯片上都有这个定时器,所以软件在不同芯片生产厂商的Cortex-M3器件间的一只工作就得以化简. 该定时器的时钟源可以是内部时钟( FCLK, CM3 上的自由运行时钟),或者是外部时钟(CM3 处理器上的 STCLK 信号).不过, STCLK 的具体来源

【STM32】串行通信原理

(1)通信接口背景知识    并行通信:         --传输原理:数据各个位同时传输         --优点:速度快         --缺点:占用引脚资源多     串行通信:         --传输原理:数据按位顺序传输         --优点:占用引脚资源少         --缺点:速度相对慢     串行通信的三种方式(按照数据发送方向):         --单工:数据传输只支持数据在一个方向上的传输.         --半双工:允许数据在两个方向上传输,但是,在某一时

关于STM32的systick定时器的详细说明

SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15).在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基.例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统:或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关.因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律. Cortex‐M3处理器内部包含了一个

STM32 的Systick操作

首先需要知道的是: 1)STM32的内核是Cortex-M3, 而Systick则是属于Cortex-M3的内核的. 2)Systick为内核提供系统时钟用,比如可以用来作为操作系统的滴答时钟.更多作用可以参考<ARM v7-M Architecture ReferenceManual> 3)Systick是个递减计数器,当计数值递减为0时可以产生Exception中断,中断号为15. 4)Systick相关的寄存器有4个. 5)Systick的控制与状态寄存器SYST_CSR的CLOCKSO

【华为云技术分享】STM32 GPIO的原理、特性、选型和配置

基本结构 STM32 GPIO是通用输入/输出端口的英文简称,其可实现输入.输出.驱动.通信等功能,STM32的I/O 端口有8种模式(4种输入模式和4种输出模式),每个 I/O 端口位支持3种最大翻转速度(2MHz.10MHz.50MHz),均可自由编程,但I/O 端口寄存器必须按 32 位字.半字(16位)或字节(8位)进行访问,具体模式如下所示: 浮空输入 上拉输入 下拉输入 模拟输入 开漏输出 推挽输出 复用功能推挽输出 复用功能开漏输出 以STM32L011为例(其他STM32处理器大

stm32用SysTick延时

SysTick是内核的一个外设,内嵌在NVIC中,它是一个24位向下递减的定时器,每计数一次的事件位1/SYSCLK(一般为72M),当重装载寄存器的值递减到0时,系统定时器就产生一次中断,循环往复,这个定时器一般用于操作系统来产生时基以维持心跳. CTRL:控制及状态寄存器 LOAD:重装载数值寄存器 VAL:当前数值寄存器 CALIB:校准数值寄存器:暂不讨论 bsp_systick.h: #ifndef __SYSTICK_H #define __SYSTICK_H #include"st

STM32的SYSTICK

1.一般操作系统都需要一个定时器来产生周期性的中断,而且最好让用户程序不能随意访问它的寄存器,以维持系统心跳的节律. 2.

STM32学习及应用笔记一:SysTick定时器学习及应用

这几年一直使用STM32的MCU,对ARM内核的SysTick计时器也经常使用,但几乎没有仔细了解过.最近正好要在移植一个新的操作系统时接触到了这块,据比较深入的了解了一下. 1.SysTick究竟是什么? 关于SysTick在STM32的资料中并没有详细的介绍,这可能由于SysTick是ARM内核的东西.在<STM32F10xxx参考手册>.<STM32F4xx参考手册>以及<STM32F7xx参考手册>中,介绍时钟的时候仅仅是在使用树上简单的画出了HCLK时钟经过8