Systick定時器簡介
- Systick定時器,是一個簡單的定時器,對於CM3,CM4內核芯片,都有Systick定時器。
- Systick定時器常用來做延時,或者實時系統的心跳時鐘。這樣可以節省MCU資源,不用浪費一個定時器。比如UCOS中,分時複用,需要一個最小的時間戳,一般在STM32+UCOS系統中,都採用Systick做UCOS心跳時鐘。
- Systick定時器就是系統滴答定時器,一個24 位的倒計數定時器,計到0 時,將從RELOAD
寄存器中自動重裝載定時初值。只要不把它在SysTick 控制及狀態寄存器中的使能位清除,就永不停息。 - SysTick定時器被捆綁在NVIC中,用於產生SYSTICK異常(異常號:15)。
- Systick中斷的優先級也可以設置。
Systick定時器的4個Systick寄存器
- CTRL SysTick 控制和狀態寄存器
- LOAD SysTick 自動重裝載除值寄存器
- VAL SysTick 當前值寄存器
- CALIB SysTick 校準值寄存器
systick定時器時鐘源配置函數
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB) //1111 1111 1111 1111 1111 1111 1111 1011
#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004) //0000 0000 0000 0000 0000 0000 0000 0100
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) ||
((SOURCE) == SysTick_CLKSource_HCLK_Div8))
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
/* Check the parameters(選擇參數) */
//注:assert_param函數目的是判斷用戶輸入的參數是否在預設的範圍中,
assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
/*判斷用戶輸入的參數*/
/*設置systick定時器的時鐘源爲內核時鐘(FCLK)HCLK,具體參數在前置的宏定義中*/
if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
{
SysTick->CTRL |= SysTick_CLKSource_HCLK;
}
/*設置systick定時器的時鐘源爲外部時鐘源(STCLK),HCLK的8分頻,具體參數在前置的宏定義中*/
Else
{
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
}
}
用查詢寄存器的位值的方式實現延時
函數的前置定義
static u8 fac_us=0; //定義了兩個靜態變量用來存儲systick定時器單位時間計數次數,詳見下文
static u16 fac_ms=0;
#define SYSCLK_FREQ_72MHz 72000000
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;
#define SysTick_CTRL_ENABLE_Pos 0
#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos)
Delay延時初始化函數
void delay_init()
{
/*配置systick定時器的時鐘源爲外部時鐘HCLK的8分頻(9MHz)*/
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us=SystemCoreClock/8000000; //設置參數
fac_ms=(u16)fac_us*1000; //設置參數
}
毫秒延時函數
void delay_ms(u16 nms)
{
u32 temp;
/*配置LOAD寄存器中存儲的倒計數次數的值,即nms毫秒要計數的次數*/
SysTick->LOAD=(u32)nms*fac_ms;
/*配置VAL寄存器當前值爲0,即清空倒數計數器*/
SysTick->VAL =0x00;
/*配置CTRL寄存器的使能位爲1,即開始計數*/
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;
/*獲取CTRL寄存器的當前值存儲在上述變量中*/
/*(temp&0x01)即獲取CTRL寄存器的使能位,定時器打開則此位爲1*/
/*(temp&(1<<16))即獲取CTRL寄存器的位16,計數完成後此位爲1,通過!運算得到0*/
/*通過&&運算上述值得到結束循環的條件爲:定時器關閉或者計數完成*/
do{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16)));
/*配置CTRL寄存器的使能位爲0,即結束計數*/
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;
/*配置VAL寄存器當前值爲0,即清空倒數計數器*/
SysTick->VAL =0X00;
}
微秒延時函數
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;
}
通過delay_init的設置,SysTick定時器的時鐘源爲外部時鐘的8分頻(9MHz),即1秒鐘計數9000000次,每次計數的時間爲1/9000000秒,通過上述計算可以得出此配置下systick定時器的每毫秒計數爲9000次,每微秒計數次數爲9次。
而SystemCoreClock通過前置的宏定義可以知道等於72000000,由此可以得出fac_us = 9 ;fac_ms=9000。用戶調用delay_ms()函數時輸入的是毫秒數,該函數爲LOAD寄存器賦的值爲毫秒數X9000得到用戶輸入的毫秒數內計數systick定時器的計數次數,綜上fac_us和fac_ms對應着systick定時器單位時間計數次數。
文中函數和部分內容摘自正點原子stm32資料與官方庫函數
自學新手,個人總結,如有出入,請多指教!