SysTick定時器
SysTick定時器,是一個簡單的定時器,對于CM3、CM4內核的芯片都有SysTick定時器。SysTick 是一個 24 位的倒計數定時器,當計數到 0 時,將從RELOAD 寄存器中自動重裝載定時初值,開始新一輪計數。只要不把它在 SysTick 控制及狀態寄存器中的使能位清除(不把Systick定時器關掉),就永不停息。SysTick定時器被捆綁在NVIC中,用于產生SYSTICK異常(異常號:15)。在以前,大多操作系統需要一個硬件定時器來產生操作系統需要的滴答中斷,作為整個系統的時基。例如,為多個任務許以不同數目的時間片,確保沒有一個任務能霸占系統;或者把每個定時器周期的某個時間范圍賜予特定的任務等,還有操作系統提供的各種定時功能,都與這個滴答定時器有關。因此,需要一個定時器來產生周期性的中斷,而且最好還讓用戶程序不能隨意訪問它的寄存器,以維持操作系統“心跳”的節律。
作用:
Systick定時器常用來做延時,或者實時系統的心跳時鐘。這樣可以節省MCU資源,不用浪費一個定時器。比如:UCOS中,分時復用,需要一個最小的時間戳,一般在STM32+UCOS系統中,都采用Systick做UCOS的心跳時鐘。
Systick寄存器:
- CLRL寄存器:Systick控制和狀態寄存器
- LOAD寄存器:Systick自動重裝載寄存器
- VAL寄存器:Systick當前值寄存器
- CALIB寄存器:Systick校準值寄存器
Systick控制和狀態寄存器-CTRL
對于STM32,外部時鐘源是HCLK(AHB總線時鐘的1/8)內核時鐘是HCLK時鐘。
配置函數:Systick_CLKSourceConfig();
Systick重裝載數值寄存器-LOAD(24位)
Systick當前值定時器-VAL
Systick校準寄存器-CAL
固件庫中的Systick相關函數:
SysTick_CLCSourConfig()//Systick時鐘源選擇,在misc.c文件中。
SysTick_config(uint32_t ticks)//初始化systick時鐘為HCLK,并開啟中斷,在core_cm3/core_cm4文件中。
Systick中斷服務函數:
void SysTick_Handler(void);
用中斷的方式實現delay延時:(比較耗費資源)
static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{ TimingDelay = nTime;while(TimingDelay != 0);
}
void SysTick_Handler(void)
{if (TimingDelay != 0x00) { TimingDelay--;}
}int main(void){ …if (SysTick_Config(SystemCoreClock / 1000)) //systick時鐘為HCLK(系統時鐘),中斷時間間隔1ms,SysTick_Config()這個函數是設置兩次中斷之間的時間。{while (1);}while(1){ Delay(200);//200ms… }
}
SysTick_Config函數:
SysTick_Config的參數,其實就是一個時鐘次數,叫systick重裝定時器的值。意思就是我要多少個1/fosc 時間后中斷一下。根據學過的物理中的時間與頻率的公式:fosc=1/T T=1/fosc ,fosc為Systick的頻率。如果STSystick時鐘頻率為:72MHz,每次的時間為:T=1/72MHz。1秒鐘為:1/(每次的時間)=1/(1/72MHz)=72 000 000次。1MHz是:1000 000。反過來講。SysTick_Config(72000)代表:72000*(1/72MHz)=1/1000=1(ms)。即定時為1ms。如果需要1S則可以通一設置一個全局變量,然后定初值得為1000,這樣每個systick中斷一次,這個全局變量減1,減到0,即systick中斷1000次,時間為:1ms1000=1S。從而實現1S的定時。 因為SysTick定時器是:24位的,最大定時時間為:2的24次方(1/72MHz)的時間,這里Systick頻率為:72MHz的情況下。
delay_init()函數:
static u8 fac_us=0;//us延時倍乘數
static u16 fac_ms=0;//ms延時倍乘數,在ucos下,代表每個節拍的ms數
void delay_init()
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.u32 reload;
#endifSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//選擇外部時鐘 HCLK/8fac_us=SystemCoreClock/8000000;//為系統時鐘的1/8 相當于72000000/8000000等于九//一次是1/systick的時鐘頻率就是1/9 us,fac_us相當于1us,這里的將9賦值給他是給寄存器LOAD計數用的,從9到1就是1us
#if SYSTEM_SUPPORT_OS //如果需要支持OS.reload=SystemCoreClock/8000000;//每秒鐘的計數次數 單位為M reload*=1000000/delay_ostickspersec;//根據delay_ostickspersec設定溢出時間//reload為24位寄存器,最大值:16777216,在72M下,約合1.86s左右 fac_ms=1000/delay_ostickspersec;//代表OS可以延時的最少單位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//開啟SYSTICK中斷SysTick->LOAD=reload; //每1/delay_ostickspersec秒中斷一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK #elsefac_ms=(u16)fac_us*1000;//非OS下,代表每個ms需要的systick時鐘數
#endif
}
void delay_us()函數:
void delay_us(u32 nus)
{ u32 temp; SysTick->LOAD=nus*fac_us; //時間加載 SysTick->VAL=0x00; //清空計數器SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器SysTick->VAL =0X00; //清空計數器
}
void delay_ms()函數:
void delay_ms(u16 nms)
{ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //時間加載(SysTick->LOAD為24bit)SysTick->VAL =0x00; //清空計數器SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器SysTick->VAL =0X00; //清空計數器
}
- T=1/1KHZ=1ms=1微秒=1/1000秒
- T=1/1MHZ=1us=1微秒=1/1000000秒
- 10MHz=1/10us=0.1us
- 20MHz=1/20us=0.05us
- 50MHz=1/50us=0.02us
- 1GHz=1ns=1納秒=1/1000000000秒
- 1MHZ=1000KHZ=1000000HZ
- 1GHZ=1000MHZ