SysTick定時器的一個簡單應用


 

SysTick即為系統定時器,又稱嘀嗒定時器,是Cortex-M3內核的一個外設,集成在NVIC中。SysTick是一個24bit的向下遞減的計數器,每計數一次的時間為1/SYSCLK(SYSCLK一般為72MHz)。

操作系統需要執行多任務管理,用SysTick產生中斷,確保單個任務不會鎖定整個系統。同時SysTick還可用於鬧鍾定時、時間測量等。

由於Cortex-M3芯片都有SysTick,所以軟件可以很容易地在Cortex-M3的產品間移植。

我們待會兒將利用SysTick產生1s的時基,讓LED一秒鍾閃爍一次,以完成SysTick的定時實驗。

注:本文所用芯片為stm32f103。

SysTick寄存器

SysTick定時器由四個寄存器控制,如圖7-1所示。

 

圖7-1

 

上圖是對四個寄存器各個位的描述。其中最后一個校准值寄存器(STK_CALIB)在定時實驗中並沒有用到,這里暫且不介紹,有興趣的讀者可以自行查找其他資料閱讀。


編程要點

  1. 向SysTick重裝載值寄存器(STK_LOAD)寫入新的重裝載值;
  2. 配置中斷優先級;
  3. 寫SysTick當前值寄存器(STK_VAL),將當前值清0;
  4. 寫SysTick控制及狀態寄存器(STK_CTRL),啟動SysTick。

SysTick屬於內核外設,其相關的寄存器定義和庫函數都在core_cm3.h中。如圖7-2為core_cm3.h頭文件里配置SysTick的源碼截圖。

圖7-2

SysTick_Config()庫函數即是按照上述的編程要點完成SysTick配置的。我們在實際項目中時可以直接調用這個庫函數來完成配置。而形參ticks用來設置STK_LOAD的值,最大不超過2^24。然后配置中斷優先級,清空STK_VAL,最后配置STK_CTRL。其中,在配置中斷優先級時調用了NVIC_SetPriority()庫函數,傳入的優先級實參為(1<<__NVIC_PRIO_BITS) - 1,其中宏__NVIC_PRIO_BITS為4,則可得其優先級為15,則可以看出其默認設置的優先級在內核外設中是最低的。

那么如果我們同時設置了內核外設和片上外設的優先級,該如何判斷孰高孰低呢?

專欄(stm32):stm32中斷初識與實踐(上)里說過,在配置外設中斷優先級時,需要先分組,再設置搶占優先級及子優先級,那么我們把內核外設的優先級也用同一配置方式分解為這三個部分。

假設配置一個外設的中斷優先級分組為3,搶占優先級為2,子優先級為1,而SysTick優先級為4。則將SysTick優先級4轉換為二進制,為0100(0b),在分組為3時,SysTick搶占優先級為010(0b),即為2,子優先級為0。我們先比較搶占優先級,發現相同,那么比較子優先級,此時SysTick子優先級為0,而我們假設的外部中斷子優先級為1,所以SysTick優先級大於假設的外設優先級(數值越小,優先級越高)。

中斷時間計算

SysTick的計數器執行的是倒計時,我們要計算中斷計數時間,需要知道計數總量(STK_LOAD的值)、時鍾源頻率等兩個參數。打個比方,這相當於我們要計算運動時間,需要知道距離和速度,那么STK_LOAD的值即為距離,時鍾源頻率即為速度。則中斷計數時間為(假設STK_LOAD的值為VALUE,時鍾源頻率為CLK,中斷計數時間為T):

T = VALUE / CLK(其中,CLK為72MHz)

當STK_LOAD的值VALUE減到0時,即可產生中斷。如果設置VALUE=72000,那么中斷一次的時間T = 72000 / 72MHz = 1ms。

定時時間計算

得出中斷一次的時間后,我們可以設置一個變量n,用來記錄中斷次數,那么最終的定時時間即為T*n。

回到開頭的實驗說明中,我們需要產生1s時基,來實現LED燈1s閃爍一次,則n為1000時滿足要求。

#define SysTick_CTRL_ENABLE_Pos 0 #define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /**  * @brief 毫秒級的定時函數  * @param n:毫秒數,如n為1000,則計時1000*1ms=1s  * @retval 無  */ void SysTick_Delay_ms(uint32_t n){ uint32_t i; SysTick_Config(72000); // 產生1ms的中斷(72000 / 72MHz = 1ms) for(i=0; i<n; i++){ while(!((SysTick->CTRL)&(1<<16))); } SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 失能SysTick } 

由於SysTick不會自動停止,所以我們需要在異常/中斷處理中將其停止,即失能SysTick。

到這里為止,一個簡單的SysTick定時實驗完成了,之后只要在main函數中調用SysTick_Delay_ms(1000)函數,即可實現1s的精確SysTick定時,而不是使用普通的不精確延時函數。


免責聲明!

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



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