/* SysTick滴答定時器一,、功能SysTick定時器是一個簡單的定時器,CM3\CM4內(nèi)核芯片都具備此定時器,。SysTick定時器常用來做延時,采用實時系統(tǒng)時則用來做系統(tǒng)時鐘,。無論用作延時還是用作系統(tǒng)心跳時鐘,,不需要太復(fù)雜的功能,SysTick即可勝任,。二,、實現(xiàn)原理SysTick定時器是一個24位的倒計數(shù),當(dāng)?shù)褂嫈?shù)為0時,,將從RELOAD寄存器中取值作為定時器的初始值,,同時可以選擇在這個時候產(chǎn)生中斷(異常號:15)。例如從RELOAD的值為999,,那么當(dāng)?shù)褂嫈?shù)為0時,,就會從復(fù)位為999繼續(xù)倒計數(shù),。 只要不把它在SysTick控制及狀態(tài)寄存器中的使能位清楚,就永不停息,,即使在睡眠模式下也能繼續(xù)工作,。三、SysTick寄存器(在 core_cm3.h 有定義,,凡是 M3 內(nèi)核的單片機都是一樣的) */#define SysTick ((SysTick_Type *) SysTick_BASE)#define SysTick_BASE (SCS_BASE + 0x0010)#define SCS_BASE (0xE000E000)typedef struct{ __IO uint32_t CTRL; // 控制及狀態(tài)寄存器 __IO uint32_t LOAD; // 重裝載數(shù)值寄存器 __IO uint32_t VAL; // 當(dāng)前計數(shù)數(shù)值寄存器 __I uint32_t CALIB; // 校準(zhǔn)寄存器} SysTick_Type;/*SysTick->CTRL: (可通過 SysTick_CLKSourceConfig() 函數(shù)設(shè)置)COUNTFLAG(16)R: 計數(shù)標(biāo)志位當(dāng)SysTick數(shù)到0,,則該位被硬件置 1,當(dāng)讀取該位時,,將被硬件清零CLKSOURCE(2)R/W: 時鐘源設(shè)置1 = 外部時鐘源(STCLK) (AHB總線時鐘的1/8(HCLK/8))0 = 內(nèi)核時鐘(FCLK) (AHB總線時鐘的頻率(HCLK))TICKINT(1)R/W: 中斷使能位1 = SysTick 倒數(shù)到0時產(chǎn)生 SysTick 異常請求0 = 數(shù)到 0 時無動作ENABLE(0)R/W: SysTick 定時器使能位(當(dāng)中斷被使能后,,需要關(guān)注 void SysTick_Handler(void) 函數(shù))SysTick_Type->LOAD: (SysTick_Config() 函數(shù)會設(shè)置該寄存器)RELOAD(23:0)R/W: 重裝載數(shù)值寄存器當(dāng)SysTick數(shù)到0,將被重裝載的值SysTick_Type->VAL: (SysTick_Config() 函數(shù)會設(shè)置該寄存器)CURRENT(23:0)R/Wc: 當(dāng)前計數(shù)數(shù)值寄存器讀取時返回當(dāng)前倒計數(shù)的值,,寫它則使之清零,,同時還會清除在 SysTick 控制及狀態(tài)寄存器中的 COUNTFLAG 標(biāo)志。四,、庫函數(shù)分析misc.c---------------------------------------------------------------------------------- */#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004)#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(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); if (SysTick_CLKSource == SysTick_CLKSource_HCLK) { SysTick->CTRL |= SysTick_CLKSource_HCLK; // 設(shè)置 CLKSOURCE 為 1 } else { SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; // 設(shè)置 CLKSOURCE 為 0 }}core_cm3.c----------------------------------------------------------------------------------#define SysTick_LOAD_RELOAD_Pos 0#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos)typedef enum IRQn{//... SysTick_IRQn = -1,//...} IRQn_Type;#define __NVIC_PRIO_BITS 4#define SysTick_CTRL_CLKSOURCE_Pos 2#define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos)#define SysTick_CTRL_TICKINT_Pos 1#define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos)#define SysTick_CTRL_ENABLE_Pos 0#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos)static __INLINE uint32_t SysTick_Config(uint32_t ticks){ if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ // 設(shè)置計數(shù)值為 ticks - 1 // 原因1:視頻說是執(zhí)行這些代碼需要時間,,所以減少一個節(jié)拍 // 原因2:我認(rèn)為是因為 SysTick 的倒計數(shù)到 0,例如設(shè)置 1000 ,,那么范圍就應(yīng)該是 999 ~ 0,。 SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; // 設(shè)置中斷優(yōu)先級 NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); SysTick->VAL = 0; // 設(shè)置時鐘源為外部時鐘源,同時開啟中斷,、并使能 SysTick 定時器 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; return (0);}/* 五,、延時應(yīng)用1、中斷方式 */static __IO uint32_t TimingDelay;void Delay(__IO uint32_t nTime){ TimingDelay = nTime; while(TimingDelay != 0);}/* 中斷服務(wù)函數(shù) */void SysTick_Handler(void){ if (TimingDelay != 0x00) { TimingDelay--; }}int main(void){// ... if (SysTick_Config(SystemCoreClock / 1000)) // 注意,,這里systick時鐘為HCLK,,中斷時間間隔1ms { while (1); } while(1) { Delay(200);//2ms// ... }}/* SysTick_Config(SystemCoreClock / 1000): (原代碼這里假設(shè)是采用時鐘源為 HCLK)這里設(shè)置的是 72000000Hz / 1000 = 72000 ticks,也就是說 SysTick 從 (72000-1) 開始倒數(shù),。每倒數(shù)完 72000 個節(jié)拍就觸發(fā)一次中斷,。一個節(jié)拍的時間為:72000000 / 72000 = 1000us == 1msSysTick_Config((SystemCoreClock / 8000000) * 1000 * 1):SysTick_Config() 會設(shè)置時鐘源為 HCLK/8 所以實際應(yīng)用中不能按照上述代碼的參數(shù)。SystemCoreClock / 8000000: 1us 的節(jié)拍數(shù)1us的節(jié)拍數(shù) * 1000: 則為 1ms 的節(jié)拍數(shù)1ms 的節(jié)拍數(shù) * 1: 設(shè)置 1ms 一個SysTick中斷,,即從 ((SystemCoreClock / 8000000) * 1000 * 1) - 1 開始倒數(shù),。2、輪詢方式 */static u8 fac_us=0; //us延時倍乘數(shù)static u16 fac_ms=0; //ms延時倍乘數(shù)void delay_init(){ SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //選擇外部時鐘 HCLK/8 fac_us = SystemCoreClock/8000000; // 為系統(tǒng)時鐘的1/8 1us = 72000000 / 8000000 = 9 個節(jié)拍 fac_ms = (u16)fac_us*1000; // 1ms 需要 9 * 1000 = 9000 個節(jié)拍}//延時 nus 微秒void delay_us(u32 nus){ u32 temp; SysTick->LOAD=nus*fac_us; //時間加載 SysTick->VAL=0x00; //清空計數(shù)器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數(shù) do { temp=SysTick->CTRL; } while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達(dá) SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;//關(guān)閉計數(shù)器 SysTick->VAL =0X00; //清空計數(shù)器}//延時nms//注意nms的范圍//SysTick->LOAD為24位寄存器,所以,最大延時為://nms<=0xffffff*8*1000/SYSCLK//SYSCLK單位為Hz,nms單位為ms//對72M條件下,nms<=1864void delay_ms(u16 nms){ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //時間加載(SysTick->LOAD為24bit) SysTick->VAL =0x00; //清空計數(shù)器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數(shù) do { temp=SysTick->CTRL; //等待時間到達(dá),,這里使用了一個小技巧,,通過(temp&0x01)檢查 SysTick 的使能位,避免 Systick 定時器被關(guān)閉而導(dǎo)致無限循環(huán) } while((temp&0x01)&&!(temp&(1<<16))); SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關(guān)閉計數(shù)器 SysTick->VAL =0X00; //清空計數(shù)器} SYSTick 定時器 |
|