關於STM32的systick定時器的詳細說明
我不得不說意法半導體確實有點風騷!甚至有點變態。我對ST文件 STM32F10XXX參考手冊的編輯水平真是不敢恭維。手冊中好多說明都是含糊不清,甚至將好多對初學者來說很重要的地方都一筆帶過,讓人著實摸不著頭腦。比如前面我說過的關於NVIC巢狀向量中斷控制器的介紹,這部分我認為是非常重要的,但當你看完他這部分介紹,你根本不會設定中斷服務程式,他有哪些暫存器都不知道,更別說去設定了,NVIC的詳細介紹是在Cotex-M3中有詳細的介紹,不多說。今天我們說的是systick定時器。
systick定時器和我上面說的情況一樣,在手冊中根本沒有介紹。我費了九牛二虎之力才在一個犄角格拉里找到systick定時器的英文版的說明。在Cotex-M3有介紹,為什麼要找STM32的介紹,是因為功能設定上還有點區別。首先看一下systick定時器的作用,下面是Cotex-M3裡的一段話:
SysTick定時器被捆綁在NVIC中,用於產生SYSTICK異常(異常號:15)。在以前,大多作業系統需要一個硬體定時器來產生作業系統需要的滴答中斷,作為整個系統的時基。例如,為多個任務許以不同數目的時間片,確保沒有一個任務能霸佔系統;或者把每個定時器週期的某個時間範圍賜予特定的任務等,還有作業系統提供的各種定時功能,都與這個滴答定時器有關。因此,需要一個定時器來產生週期性的中斷,而且最好還讓使用者程式不能隨意訪問它的暫存器,以維持作業系統“心跳”的節律。
Cortex‐M3處理器內部包含了一個簡單的定時器。因為所有的CM3晶片都帶有這個定時器,軟體在不同 CM3器件間的移植工作得以化簡。該定時器的時鐘源可以是內部時鐘(FCLK,CM3上的自由執行時鐘),或者是外部時鐘( CM3處理器上的STCLK訊號)。不過,STCLK的具體來源則由晶片設計者決定,因此不同產品之間的時鐘頻率可能會大不相同,你需要檢視晶片的器件手冊來決定選擇什麼作為時鐘源。(知道我為什麼找ST關於systick的說明了吧)。
下面介紹STM32中的systick,Systick 部分內容屬於NVIC控制部分,一共有4個暫存器,名稱和地址分別是:
STK_CSR, 0xE000E010 -- 控制暫存器
STK_LOAD, 0xE000E014 -- 過載暫存器
STK_VAL, 0xE000E018 -- 當前值暫存器
STK_CALRB, 0xE000E01C -- 校準值暫存器
首先看STK_CSR控制暫存器:暫存器內有4個位t具有意義
第0位:ENABLE,Systick 使能位 (0:關閉Systick功能;1:開啟Systick功能)
第1位:TICKINT,Systick 中斷使能位 (0:關閉Systick中斷;1:開啟Systick中斷)
第2位:CLKSOURCE,Systick時鐘源選擇 (0:使用HCLK/8 作為Systick時鐘;1:使用HCLK作為Systick時鐘)
第3位:COUNTFLAG,Systick計數比較標誌,如果在上次讀取本暫存器後,SysTick 已經數到了0,則該位為1。如果讀取該位,該位將自動清零
STK_LOAD 過載暫存器:
Systick是一個遞減的定時器,當定時器遞減至0時,過載暫存器中的值就會被重灌載,繼續開始遞減。STK_LOAD 過載暫存器是個24位的暫存器最大計數0xFFFFFF。
STK_VAL當前值暫存器:
也是個24位的暫存器,讀取時返回當前倒計數的值,寫它則使之清零,同時還會清除在SysTick 控制及狀態暫存器中的COUNTFLAG 標誌。
STK_CALRB 校準值暫存器:
這個暫存器好像目前的水平我還用不到,大體意思明白點,把英文說明放這吧:
位31 NOREF :1=沒有外部參考時鐘(STCLK 不可用)0=外部參考時鐘可用
位30 SKEW:1=校準值不是準確的1ms 0=校準值是準確的1ms
位[23:0] :Calibration value
Indicates the calibration value when the SysTick counter runs on HCLK max/8 as external clock. The value is product dependent, please refer to the Product Reference Manual, SysTick Calibration Value section. When HCLK is programmed at the maximum frequency, the SysTick period is 1ms. If calibration information is not known, calculate the calibration value required from the frequency of the processor clock or external clock.
SysTick定時器除了能服務於作業系統之外,還能用於其它目的:如作為一個鬧鈴,用於測量時間等。要注意的是,當處理器在除錯期間被喊停(halt)時,則SysTick定時器亦將暫停運作。
下面我們就應用SysTick定時器來裸奔,把它作為一個定時器來用,還是老一套,在暫存器標頭檔案中新增定義暫存器:
//*****************************************************************
//* SystemTick-Register
//*******************************************************************
#define SYSTICK_TENMS (*((volatile unsigned long *)0xE000E01C))
#define SYSTICK_CURRENT (*((volatile unsigned long *)0xE000E018))
#define SYSTICK_RELOAD (*((volatile unsigned long *)0xE000E014))
#define SYSTICK_CSR (*((volatile unsigned long *)0xE000E010))
配置systick暫存器:
void SysTick_Configuration(void)
{
SYSTICK_CURRENT=0; //當前值暫存器
SYSTICK_RELOAD=20000; //重灌載暫存器,系統時鐘20M中斷一次1mS
SYSTICK_CSR|=0x06;// HCLK作為Systick時鐘,Systick中斷使能位
}
中斷處理:
void SysTick_Handler(void) //中斷函式
{
extern unsigned long TimingDelay; // 延時時間,注意定義為全域性變數
SYSTICK_CURRENT=0;
if (TimingDelay != 0x00)
TimingDelay--;
}
利用systick的延時函式:
unsigned long TimingDelay; // 延時時間,注意定義為全域性變數
void Delay(unsigned long nTime) //延時函式
{
SYSTICK_CSR|=0x07; // 使能SysTick計數器
TimingDelay = nTime; // 讀取延時時間
while(TimingDelay != 0); // 判斷延時是否結束
SYSTICK_CSR|=0x06;// 關閉SysTick計數器
}
int main()
{
SystemInit0(); //系統(時鐘)初始化
stm32_GpioSetup (); //GPIO初始化
SysTick_Configuration(); //配置systick定時器
while(1)
{
GPIO_PORTB_ODR|=(1<<5);
Delay(1000); //1S
GPIO_PORTB_ODR&=~(1<<5);
Delay(1000); //1S
}
}
完成!Delay(1000);實現了1S的精確延時,利用Delay(unsigned long nTime);配合systick定時器可以實現任意時間的精確延時,當然通過定時器TIMx也是可以這樣做的,我只是用它來說明systick定時器的用法。