STM32-Systick滴答定時器-延時函數


1.STM32-Systick滴答定時器

  • Systick定時器,是一個簡單的定時器,對於ST的CM3,CM4,CM7內核芯片,都有Systick定時器。

  • Systick定時器常用來做延時,或者實時系統的心跳時鍾。這樣可以節省MCU資源,不用浪費一個定時器。比如UCOS中,分時復用,需要一個最小的時間戳,一般在STM32+UCOS系統中,都采用Systick做UCOS心跳時鍾。

  • Systick定時器就是系統滴答定時器,一個24 位的倒計數定時器,計到0 時,將從RELOAD 寄存器中自動重裝載定時初值。只要不把它在SysTick 控制及狀態寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。

  • SysTick定時器被捆綁在NVIC中,用於產生SYSTICK異常(異常號:15)。

  • Systick中斷的優先級也可以設置。

  • 4個Systick寄存器

    CTRL             SysTick 控制和狀態寄存器  
    LOAD             SysTick 自動重裝載除值寄存器 
    VAL              SysTick 當前值寄存器  
    CALIB            SysTick 校准值寄存器
    

可在core-core_cm7.h文件中找到

typedef struct
{
  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
  __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
  __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
} SysTick_Type;

SysTick 控制和狀態寄存器- CTRL:

在這里插入圖片描述

對於STM32,外部時鍾源是 HCLK(AHB總線時鍾)的1/8。內核時鍾是 HCLK時鍾。配置函數:HAL_SYSTICK_CLKSourceConfig();

SysTick重裝載數值寄存器-LOAD

在這里插入圖片描述

SysTick當前數值寄存器-VAL

在這里插入圖片描述

HAL庫中的Systick相關函數:

stm32f7xx_hal_cortex.c文件中:HAL_SYSTICK_CLKSourceConfig () ; //Systick時鍾源選擇

如果SysTick的時鍾源自HCLK,假設外部晶振為25M,倍頻到216MHZ,那么SysTick的時鍾即為216MHZ,也就是SysTick的計數器VAL每減1,就代表時間過了1/216us。

void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource) { /* Check the parameters */ assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource)); if (CLKSource == SYSTICK_CLKSOURCE_HCLK) { SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK; } else { SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK; } } 

可以看一下CLKSource可以有哪幾種:找到IS_SYSTICK_CLK_SOURCE的定義,發現可以為SYSTICK_CLKSOURCE_HCLK和SYSTICK_CLKSOURCE_HCLK_DIV8,也就是不分頻或者8分頻。

#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SYSTICK_CLKSOURCE_HCLK) || \ ((SOURCE) == SYSTICK_CLKSOURCE_HCLK_DIV8)) 

core_cm7.h文件中:SysTick_Config (uint32_t ticks) //初始化systick,時鍾為HCLK,並開啟中斷。

ticks:經過多少個systick周期發生一次中斷。用來配置SysTick定時器經過多少個ticks發生一次中斷。

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); /* Reload value impossible */ } SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0UL); /* Function successful */ } 

首先看到SysTick_LOAD_RELOAD_Msk,由於Systick是一個24 位的倒計數定時器,所以值不能太大。

#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) 

Systick中斷服務函數:void SysTick_Handler (void);

2.delay函數

//初始化延遲函數 //當使用ucos的時候,此函數會初始化ucos的時鍾節拍 //SYSTICK的時鍾固定為AHB時鍾的1/8 //SYSCLK:系統時鍾頻率 void delay_init(u8 SYSCLK) { #if SYSTEM_SUPPORT_OS //如果需要支持OS. u32 reload; #endif HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick頻率為HCLK fac_us=SYSCLK; //不論是否使用OS,fac_us都需要使用 #if SYSTEM_SUPPORT_OS //如果需要支持OS. reload=SYSCLK; //每秒鍾的計數次數 單位為K reload*=1000000/delay_ostickspersec; //根據delay_ostickspersec設定溢出時間 //reload為24位寄存器,最大值:16777216,在216M下,約合77.7ms左右 fac_ms=1000/delay_ostickspersec; //代表OS可以延時的最少單位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//開啟SYSTICK中斷 SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中斷一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK #endif } 

在main中調用delay_init(216);//延時初始化。1微秒等於10的負6次方秒,1MHZ等於10^6赫茲。

fac_us=SYSCLK;系統時鍾是216MHZ,fac_us=216意思是:systick運行1us,需要多少個systick周期。由於systick是216MHZ,所以需要216個周期。后面如果需要延時n個微秒,只需要n*fac_us即可。由於設置的SysTick頻率為HCLK,所以調用delay_init函數中的參數SYSCLK就是216 。

delay_us函數思路:

在循環里檢測當前值,如果當前值小於前一次的值,說明沒有減到0,通過told-tnow就可以知道當前跑了幾個周期。否則,說明已經溢出了,也就是說當前跑了reload-tnow+told個周期。最后如果時間超過/等於要延遲的時間,則退出。
在這里插入圖片描述

//延時nus //nus:要延時的us數. //nus:0~204522252(最大值即2^32/fac_us@fac_us=21) void delay_us(u32 nus) { u32 ticks; u32 told,tnow,tcnt=0; u32 reload=SysTick->LOAD; //LOAD的值 ticks=nus*fac_us; //需要的節拍數 delay_osschedlock(); //阻止OS調度,防止打斷us延時 told=SysTick->VAL; //剛進入時的計數器值 while(1) { tnow=SysTick->VAL; if(tnow!=told) { if(tnow<told)tcnt+=told-tnow; //這里注意一下SYSTICK是一個遞減的計數器就可以了. else tcnt+=reload-tnow+told; told=tnow; if(tcnt>=ticks)break; //時間超過/等於要延遲的時間,則退出. } }; delay_osschedunlock(); //恢復OS調度 } 
Markdown 4346 字數 178 行數 當前行 1, 當前列 0
HTML 3796 字數 111 段落


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM