1. 程式人生 > >STM32 F4 (8) Systick滴答定時器-延時函式講解 QQ群 860099671

STM32 F4 (8) Systick滴答定時器-延時函式講解 QQ群 860099671

 SysTick定時器適用所有的STM32開發板,這節課講解SysTick定時器產生的 延時函式,STM32開發指南5.1小節有有關SysTick相關的 介紹,在程式中在delay資料夾中,SysTick定時器是核心級別的,這個定時器很簡單,主要用來延時和用作實時系統裡面的心跳時鐘 可以節省微控制器資源,SysTick定時器就是系統滴答定時器,是一個24位的倒計數定時器,當他計數到0時就會從RELOD暫存器(重灌載暫存器)重新裝載計數初值,由此迴圈。只要 不把他的使能 位清除,他就會永不停息的工作,即使在睡眠模式下也能正常工作。

   SysTick定時器它是捆綁在NVIC中,可以產生SysTick異常,SysTick也可以產生中斷 ,可以設定中斷優先順序,可編寫中斷服務函式

SysTick有四個暫存器,前面3個比較常用,LOAD放重灌載值,VAL暫存器一個時鐘週期會減一,一直減到0之後又會從這個LOAD暫存器重新載入到VAL暫存器, 這樣去迴圈

SysTick控制和狀態暫存器 CTRL   下面這個表在Cortex M3權威指南里有,

位0 (ENABLE)SysTick定時器的使能位,

位1   (TICKINT) 當VAL暫存器計數到0時是否要產生中斷

為1  產生中斷        為0不產生中斷

位2(CLKSOURCE)時鐘源,為 0使用外部時鐘源(STCLK)   為1 使用核心時鐘(FCLK)

對於STM32而言    0.使用外部時鐘源是HCLK(AHB匯流排時鐘的1/8)

                             1.核心時鐘是HCLK時鐘

這裡M3經過   Systeminit()後系統時鐘是72M,那麼SysTick時鐘就是72/8=9M

       M4經過   Systeminit()後系統時鐘是168M  那麼SysTick時鐘就是168/8=21M

SysTick定時器的時鐘源可以由SysTick_CLKSourceConfig()配置,由這個函式的入口引數確定使用哪一個作為時鐘源。這裡

對於M3\M4都是一樣的,因為它是屬於核心級別的,都是屬於同一 SysTick定時器。

位16  (COUNTFLAG)  如果SysTick計數到0,該位為1,如果讀取該位,該位將自動清零 

第二暫存器叫做  重灌載數值暫存器-LOAD,是一個24位暫存器

第三個暫存器是 SysTick當前值暫存器-VAL,一個週期減一

Systick相關庫函式

SysTick_CLKSourceConfig();  是配置CTL暫存器的,用於時鐘源的選擇

SysTick_Config(uint32_t ticks)  這個函式會開啟SysTick 中斷, ticks是一秒鐘產生中斷的次數

這裡的中斷函式 void SysTick_Handler(void);  對於M3/M4都是一樣的

下面看程式碼  這個 函式有一個入口引數叫 Systick_CLKSource

實際上是配置CTRL暫存器位2(CLKSOURCE),   為0 就是配置為外部時鐘 HCLK(AHB匯流排時鐘)的1/8

                                                                                為1就是配置為核心時鐘,就是HCLK

還有一個函式在core_cm4.h/core_cm3.h裡面的SysTick_Config(uint32_ticks)這個程式碼的作用;初始化SysTick相關的暫存器,並且開啟SysTick相關的暫存器,入口引數ticks.,也就是說ticks個時鐘週期產生一次中斷。

程式碼的第一行對這個ticks的值進行一個有效性判斷,因為這個ticks的值不能是無限大,因為ticks最終是要寫到LOAD暫存器的,從LOAD暫存器被載入到這個VAL暫存器,ticks的值 不能大於

 我們可以看到是6個F(就是2的24次方-1),也就是ticks不能大於2的24次方。

將 ticks-1賦值給這個load暫存器(也就是重灌載暫存器的值設定為ticks-1),那麼他就會載入到這個VAL暫存器當中,當VAL的值計數到0,LOAD暫存器又從新將初值裝載到VAL當中。

接下來 是設定優先順序,那麼設定優先順序在NVIC相關的視訊會去講解

接著把這個VAL設定為0, 為什麼要設定為0呢?因為當我們這個VAL值為0的時候他會從新去載入計數初值,所以這裡初始化的時候把它設定為0,後面如果開啟了SysTick定時器,第一次他就會把初值載入到VAL當中。

上圖程式碼就是就是開啟這個SysTick定時器,1設定 時鐘源    2開啟中斷  3使能SysTick定時器。

對於Systick庫函式,有一個·SysTick_Config(uint32_ticks)利用中斷實現的delay函式

這裡函式的備註錯了,應該是200ms的延時

上面這段程式碼作簡單講解

1.首先 在主函式裡面他會呼叫一個SysTick_Config(uint32_ticks)這樣的一個函式,入口引數是ticks,這裡SysTick的時鐘是HCLK是168M,因為要定時1ms,那麼通過計算就是:168000000/1000,然後是 上面寫的一個delay函式,在這個函式前面定義了一個全域性變數,TimerDelay(168M時鐘,1s計數168000 000次,那麼1ms就計數計數168 000次,所以168M時鐘/1000=1ms 延時)

上面的程式碼中入口引數是200,就等待他為0才能夠結束。

函式功能:每1ms產生一次中斷,進一次中斷TimingDelay就-1,直到TimingDelay為0就延時了200ms。

正點原子的系統資料夾 的delay.c是是使用查詢的方式實現延時的,在delay.h裡面有三個函式

1,。delay_init(u8 SYSCLK)  這是對SysTick進行初始化,然後是兩個 毫秒和微秒的延時。因為正點原子的delay.c裡面支援ucos作業系統,所以有一部分程式碼是通過巨集定義來支援的。

上圖中 的兩個變數在初始化函式當中我們會設定他的值,假如系統時鐘是 168M,SysTick的時鐘頻率是系統時鐘的8分頻,也就是21M,那麼  fac_us 含義就是我們要延時1us要用多少個SysTick時鐘週期?

因為系統時鐘是21M,所以就是21時鐘週期是1us。

那麼延時1ms要多少個時鐘週期?  就是21000個時鐘週期

這裡SYSCLK和HCLK是一樣的為168,

這一行程式碼是UCOS相關的,暫時不看。

上圖入口引數, 選擇HCLK的8分頻作為SysTick的時鐘頻率,那麼SysTick的時鐘頻率就是21M,

這裡SYSCLK/8=168/8=21,所以fac_us=21,也就是說1us需要21個時鐘週期。

上圖這一段程式碼也是ucos相關的暫時不看。

到最後這個就是設定ms的因子。下面就開始寫我們的ms、us的延時函式,有3個函式

delay_us這個函式他就有一個入口函式叫nus。就告訴我們呼叫這個函式輸入100就是100us

怎麼實現呢?

也就是讓初值LOAD=nms*fac_ms

使能SysTick計數器,讓LOAD暫存器的值載入到VAL暫存器,並開始計數,當計數到0時,CTRL暫存器就有一個位16標誌位,計數到0就會置1.之後我們就關閉計數器。然後再清空計數器。

注意:延時時間是有一個範圍的,怎麼來確定這個範圍呢?LOAD暫存器是一個24位的暫存器,也就是說他的最大值是2的24次方-1,所以nus*fac_us不能大於79815us這個值

這裡將入口引數除以540是為什麼呢?,目的是增加延時時間的範圍,比如說我們要延時一個任意長度的延時時間,那麼我們這裡實際上就把他切成了540毫秒一份,比如說你要延時1000ms,他就先延時540ms再延時460ms這樣就延時了1000ms。

這個函式和微秒 的配置是一樣的。這裡不在介紹。