HAL庫與Cubemx系列|Systick-系統滴答定時器詳解

嵌入式實驗基地發表於2021-06-09

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,即可獲得原始碼哦~

相關文章