Systick是什么?
關於Systick,在Context-M3權威指南中如此描述:
SysTick定時器被捆綁在NVIC中,用於產生SYSTICK異常(異常號: 15)。在以前,大多操作系統需要一個硬件定時器來產生操作系統需要的滴答中斷,作為整個系統的時基。例如,為多個任務許以不同數目的時間片,確保沒有一個任務能霸占系統;或者把每個定時器周期的某個時間范圍賜予特定的任務等,還有操作系統提供的各種定時功能,都與這個滴答定時器有關。因此,需要一個定時器來產生周期性的中斷,而且最好還讓用戶程序不能隨意訪問它的寄存器,以維持操作系統“心跳”的節律。
SysTick定時器能產生中斷, CM3為它專門開出一個異常類型,並且在向量表中有它的一席之地。它使操作系統和其它系統軟件在CM3器件間的移植變得簡單多了,因為在所有CM3產品間對其處理都是相同的。
SysTick 是一個 24 位的倒計數定時器,當計到 0 時,將從 RELOAD 寄存器中自動重裝載定時初值。只要不把它在 SysTick 控制及狀態寄存器中的使能位清除, 就永不停息,圖 13.1 中小結了 SysTick的相關寄存器。
這是定義在core_cm3.h中的結構體:
SysTick 的最大使命,就是定期地產生異常請求,作為系統的時基。 OS 都需要這種“滴答” 來推動任務和時間的管理。 如欲使能 SysTick 異常, 則把 STCSR.TICKINT 置位。 另外, 如果向量表被重定位到 SRAM 中,還需要為 SysTick 異常建立向量,提供其服務例程的入口地址。
Systick如何使用?
前面說了那么多,Systick到底是什么,小伙伴們是不是已經明白了呢?其實,簡單一句話,就是“心跳”,CPU以心跳為依據分配要做的事情,嘀噠...嘀噠...嘀噠...
cubemx配置Systick
來來來,實踐是檢驗真理的唯一標准,沒有實踐的理論就是耍流氓~~
Systick是系統的“心跳”,為系統提供着時基來源,cubemx中是已經為我們勾選了的,默認的時基是來源於Systick
當然了,條條大路通羅馬,Systick可以作為時基,但卻不是唯一的,不信你看,實際上有這么多的定時器都可以用來作為時基來源的,移植過操作系統的小伙伴一定不陌生,本次,我們只介紹關於Systick的功能~
- 時鍾配置
關於時鍾配置的詳細講解,請參看:CubeMX的正確打開方式 一文
- 串口配置
關於串口配置的詳細解釋,請參看:CubeMX的正確打開方式 一文
- Systick中斷
可以看到,Systick的中斷是默認已經開啟了的,直接使用即可
Systick代碼詳細解析
結合生成的工程,來看看Systick的時鍾配置以及工作流程,systick首先在HAL_Init()函數中被提到,被cue來干嘛呢,接下來跟進去看看
從英文解釋中(別說看不懂哈),Systick被配置為系統時基,並且被配置為了1ms,做技術,要有刨根問底的精神,奧利給,繼續跟進去看看
這段英文解釋很重要,外設中斷進程調用HAL_Delay的時候,要特別注意中斷的優先級問題,如果systick的中斷優先級低於外設中斷優先級,會導致一直在外設中斷中阻塞,如果外設中調用了HAL_Delay(),一定要保證Systick的中斷優先級高於外設中斷優先級,但是,小飛哥是極其不建議在中斷中調用HAL_Delay()函數的
明明是在說Systick的事情,怎么牽扯到HAL_Delay()函數了呢,那就再來看看,HAL_Delay()是如何實現的呢?打開HAL_Delay(),可以看到,實際上是通過uWTick這個全局變量不斷增加,比較來實現的延時,那么uWTick是在哪里增加的呢?
好家伙,轉了十萬八千里,最終還是在Systick中斷中進行增加的,默認配置的是Systick 1ms中斷,這下知道了我們調用的HAL_Delay(),為什么是1ms了吧,繞了那么一大圈,是不是有點想打人呢~
默認配置的是1ms中斷周期,那我們HAL_Delay()的最小單位是1ms,如果想獲得1us的中斷周期,該如何調整呢?且往下看,這是我們自定義的systick周期配置函數,一步一步來看
先來看systick的時鍾來源,時鍾來源為HCLK或者是HCLK的8分頻,小飛哥實驗選擇的是HCLK,72MHZ,確定了systick的時鍾源,接下來配置systick的中斷周期
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
再來看這個函數,分析之前,我們先來看看systick的中斷周期時間是怎么計算的,T=ReloadValue10001/72000000ms
這是默認的配置1ms,主頻是72MHZ,uwTickFreq默認是1KHZ,根據上面的分析計算,算下來T = (72MHZ/1000)1/72MHZ=1000/72MHZ(1/72MHZ)=1/1000s=1ms,你看懂了嗎?
HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)
根據上面的分析,我們想要1us、10ms、100ms....的中斷周期怎么辦,那就根據上面的計算公式算吧,那這么修改后,HAL_Delay不就可以實現us延時了嘛,實現當然是能實現,但中斷是不是過於頻繁了呢,1us一個中斷誒,那怎么實現呢,請查看,關於HAL庫us延時的3種實現方式
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); //1ms
到此,關於systick的工作流程就算是介紹差不多了,還有最后一步,Systick中斷回調函數需要添加到中斷回調句柄中
可以看到systick中斷回調函數依然是_weak修飾符,意思就是我們自己一個一樣名字的函數,不會報錯
我們自己重新定義回調函數,處理中斷事務,好的編程習慣,中斷置標志,所有的邏輯處理放在中斷外處理,建議這樣做
while中不斷查詢標志
測試結果
間隔100ms,打印systick test,測試OK,over
關於Embeded-party
歡迎加入群聊Embeded-party,這里有一群可愛的人兒,很多有意思的設計,等着你的加入哦
資料獲取
公眾號后台回復,systick,即可獲得源碼哦~