操作系統需要執行多任務管理,用SysTick產生中斷,確保單個任務不會鎖定整個系統。同時SysTick還可用於鬧鍾定時、時間測量等。
由於Cortex-M3芯片都有SysTick,所以軟件可以很容易地在Cortex-M3的產品間移植。
我們待會兒將利用SysTick產生1s的時基,讓LED一秒鍾閃爍一次,以完成SysTick的定時實驗。
注:本文所用芯片為stm32f103。
SysTick寄存器
SysTick定時器由四個寄存器控制,如圖7-1所示。

上圖是對四個寄存器各個位的描述。其中最后一個校准值寄存器(STK_CALIB)在定時實驗中並沒有用到,這里暫且不介紹,有興趣的讀者可以自行查找其他資料閱讀。
編程要點
- 向SysTick重裝載值寄存器(STK_LOAD)寫入新的重裝載值;
- 配置中斷優先級;
- 寫SysTick當前值寄存器(STK_VAL),將當前值清0;
- 寫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定時,而不是使用普通的不精確延時函數。