SysTick系統定時器(功能框圖和優先級配置)


      SysTick—系統定時器是屬於 CM3 內核中的一個外設,內嵌在 NVIC 中。系統定時器是一個 24bit (2^24)的向下遞減的計數器,計數器每計數一次的時間為 1/SYSCLK,一般我們設置系統時鍾 SYSCLK 等於 72M。當重裝載數值寄存器的值遞減到 0 的時候,系統定時器就產生一次中斷,以此循環往復。

     因為 SysTick 是屬於 CM3 內核的外設,所以所有基於 CM3 內核的單片機都具有這個系統定時器,使得軟件在 CM3 單片機中可以很容易的移植。系統定時器一般用於操作系統,用於產生時基,維持操作系統的心跳.

1

    SysTick的執行過程:counter在時鍾的驅動下,從reload初值開始往下遞減計數到0(在遞減的過程中值可以在STK_VAL中查看到),產生中斷和置位COUNTFLAG標志。然后又從reload 值開始重新遞減計數,如此循環。

 

SysTick相關寄存器

     SysTick—系統定時器有 4 個寄存器(CTRL LOAD VAL CALIB),簡要介紹如下。在使用 SysTick 產生定時的時候,只需要配置前三個寄存器,最后一個校准寄存器不需要使用。

 2

 

SysTick寄存器結構體

      SysTick寄存器(在固件庫文件:core_cm3.h中定義)

typedef struct{
   _IO uint32_t  CTRL;      /*控制及狀態寄存器*/
  _IO uint32_t   LOAD;      /*重裝載數值寄存器*/
  _IO uint32_t   VAL;       /*當前數值寄存器*/
 _IO uint32_t   CALIB;      /*校准寄存器*/


}

SysTick庫函數

      SysTick配置庫函數(在固件庫文件:core_cm3.h中定義)

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
 {
 // 不可能的重裝載值,超出范圍
 if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) {
 return (1UL);
 }

 // 設置重裝載寄存器
 SysTick->LOAD = (uint32_t)(ticks - 1UL);

 // 設置中斷優先級,默認優先級最低 __NVIC_PRIO_BITS 4(1111)系統定時器此時設置的優先級在內核外設中是最低的
 NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);

 // 設置當前數值寄存器
 SysTick->VAL = 0UL;

 // 設置系統定時器的時鍾源為 AHBCLK=72M
 // 使能系統定時器中斷
 // 使能定時器
 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
21 SysTick_CTRL_TICKINT_Msk |
22 SysTick_CTRL_ENABLE_Msk;
23 return (0UL);
24 }

      用固件庫編程的時候我們只需要調用庫函數 SysTick_Config()即可,形參 ticks 用來設置重裝載寄存器的值,最大不能超過重裝載寄存器的值 2^24,當重裝載寄存器的值遞減到 0 的時候產生中斷,然后重裝載寄存器的值又重新裝載往下遞減計數,以此循環往復。緊隨其后設置好中斷優先級最后配置系統定時器的時鍾等於 AHBCLK=72M,使能定時器和定時器中斷,這樣系統定時器就配置好了,一個庫函數搞定。 

配置 SysTick 中斷優先級

     在 SysTick_Config()庫函數還調用了固件庫函數 NVIC_SetPriority()來配置系統定時器的中斷優先級,該庫函數也在 core_m3.h 中定義,原型如下

__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
 {
 if ((int32_t)IRQn < 0) {
 SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] =(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
 } else {
 NVIC->IP[((uint32_t)(int32_t)IRQn)] =(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
 }
 }

      函數首先先判斷形參 IRQn 的大小,如果是小於 0,則表示這個是系統異常系統異常的優先級由內核外設 SCB 的寄存器 SHPRx 控制,如果大於 0 則是外部中斷,外部中斷的優先級由內核外設 NVIC 中的 IPx 寄存器控制。

      因為 SysTick 屬於內核外設,跟普通外設的中斷優先級有些區別,並沒有搶占優先級和子優先級的說法。在 STM32F103 中,內核外設的中斷優先級由內核 SCB 這個外設的寄存器:SHPRx(x=1.2.3)來配置。

      SPRH1-SPRH3 是一個 32 位的寄存器,但是只能通過字節訪問,每 8 個字段控制着一個內核外設的中斷優先級的配置。在 STM32F103 中,只有位 7:3 這高四位有效,低四位沒有用到,所以內核外設的中斷優先級可編程為:0~15,只有 16 個可編程優先級,數值越小,優先級越高。如果軟件優先級配置相同,那就根據他們在中斷向量表里面的位置編號來決定優先級大小,編號越小,優先級越高。 (系統定時器此時設置的優先級在內核外設中是最低的.)

     

外設中斷優先級和內核外設優先級比較

     內核優先級是不分搶占優先級和子優先級,但不是內核外設的優先級就一定比外設的優先級高.

    判別方法:根據內核外設設置優先級0-15的值,把內核外設的中斷優先級的四個位按照外設的中斷優先級來分組來解析即可,即人為的分出搶占優先級和子優先級。

     比如配置一個外設的中斷優先級分組為 2,搶占優先級為 1,子優先級也為 1,systick 的優先級為固件庫默認配置的 15。當我們比較內核外設和片上外設的中斷優先級的時候,我們只需要抓住 NVIC 的中斷優先級分組不僅對片上外設有效,同樣對內核的外設也有效。我們把 systick 的優先級 15 轉換成二進制值就是 1111(0b),又因為 NVIC 的優先級分組 2,那么前兩位的 11(0b)就是 3,后兩位的 11(0b)也是 3。無論從搶占還是子優先級都比我們設定的外設的優先級低。如果當兩個的軟件優先級都配置成一樣,那么就比較他們在中斷向量表中的硬件編號,編號越小,優先級越高。

SysTick 初始化函數

void SysTick_Init(void)
{
 /* SystemFrequency / 1000 1ms 中斷一次
 * SystemFrequency / 100000 10us 中斷一次
 * SystemFrequency / 1000000 1us 中斷一次
 */
 if (SysTick_Config(SystemCoreClock / 100000)) {
 /* Capture error */
  while (1);
   }
}

     SysTick 初始化函數由用戶編寫,里面調用了 SysTick_Config()這個固件庫函數,通過設置該固件庫函數的形參,就決定了系統定時器經過多少時間就產生一次中斷

SysTick定時時間計算

    時間單位換算: 1s = 1000ms = 1000 000 us = 1000 000 000ns

          t = reload * ( 1/clk )

  1. Clk = 72M時,t = (72) *(1/ 72 M )= 1US
  2. Clk = 72M時,t = (72000) *(1/ 72 M )= 1MS


免責聲明!

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



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