一、SysTick是什么?
Systick定時(shí)器是一個(gè)24bit的倒計(jì)時(shí)(向下計(jì)數(shù))定時(shí)器,功能就是實(shí)現(xiàn)簡單的延時(shí)。
SysTick 是一種系統(tǒng)定時(shí)器,通常在嵌入式系統(tǒng)中使用。它是 ARM Cortex-M 處理器的一個(gè)特殊定時(shí)器,用于提供系統(tǒng)級(jí)的定時(shí)服務(wù)。SysTick 可以用于生成定時(shí)中斷,以便執(zhí)行特定的任務(wù)或進(jìn)行系統(tǒng)級(jí)的時(shí)間跟蹤。
例如:計(jì)數(shù)初值為100,經(jīng)過一個(gè)時(shí)鐘周期后,計(jì)數(shù)值減一,即99,98,97……1,0;計(jì)數(shù)至0后,又重新開始從100開始倒計(jì)數(shù)至0。? 可以借此做精準(zhǔn)延時(shí)。
二、SysTick框架圖
因?yàn)镾ysTick是屬于內(nèi)核的一部分,其被捆綁在NVIC中,用于產(chǎn)生SYSTICK異常。
三、SysTick組成
? SysTick包含四個(gè)寄存器,都是24位的寄存器,分別是:
(1) SysTick->CTRL
SysTick控制及狀態(tài)寄存器 (-- 0xE000 E010
(2) SysTick->LOAD
SysTick重裝載寄存器 – 0xE000 E014
(3) SysTick->VAL
SysTick當(dāng)前值寄存器 – 0xE000 E018
(4) SysTick->CALIB
SysTick校準(zhǔn)值寄存器 – 0xE000 E01C
四、SysTick時(shí)鐘知識(shí)點(diǎn)
(1)首先明白頻率(Hz)與時(shí)間(S)的轉(zhuǎn)換。
●1Hz代表每秒周期震動(dòng)1次, 60Hz代表每秒周期震動(dòng)60次。假如滴答時(shí)鐘的頻率是72MHZ,72MHz表示每秒鐘有72,000,000個(gè)時(shí)鐘周期。那讓滴答時(shí)鐘計(jì)1次,時(shí)間過去了1/72μs,也就是一個(gè)時(shí)鐘周期為1/72000000 s =1/72 us。
●定時(shí)1us,就需要72個(gè)時(shí)鐘周期。
●定時(shí)1s,就需要72000個(gè)時(shí)鐘周期。
(2)為什么需要裝載預(yù)期值-1?
答:裝載值就是裝載的時(shí)鐘周期個(gè)數(shù)。SysTick 定時(shí)器的計(jì)數(shù)是從 LOAD 裝載值寄存器的值遞減到零的,所以如果你希望實(shí)現(xiàn) n 個(gè)時(shí)鐘周期的延時(shí),你需要將 LOAD 寄存器設(shè)置為 n - 1。如系統(tǒng)時(shí)鐘頻率為72MHz,經(jīng)過8分頻后,頻率為9MHz。即1s震動(dòng)9000 000個(gè)周期。所以裝載值為8999 000,計(jì)數(shù)器從8999000減到0,總共經(jīng)過 9000000 個(gè)時(shí)鐘周期,則正好為1s的時(shí)間,即實(shí)現(xiàn)定時(shí)1s。
(3)為什么選擇經(jīng)過8分頻的外部時(shí)鐘,而不選擇內(nèi)部時(shí)鐘?
答:選擇使用外部時(shí)鐘而不是內(nèi)部時(shí)鐘,是為了保證定時(shí)器的精度和穩(wěn)定性。
內(nèi)部時(shí)鐘是由微控制器內(nèi)部提供的時(shí)鐘源,通常頻率相對(duì)較低。在某些情況下,使用內(nèi)部時(shí)鐘作為SysTick的時(shí)鐘源可能會(huì)導(dǎo)致定時(shí)器的溢出時(shí)間過長,無法滿足精確的延時(shí)需求。
外部時(shí)鐘,例如外部晶體振蕩器或主芯片提供的外部時(shí)鐘信號(hào),具有較高的頻率和穩(wěn)定性。使用外部時(shí)鐘作為SysTick的時(shí)鐘源可以提供更高的精度和可靠性。對(duì)于需要較準(zhǔn)確的延時(shí)操作或時(shí)間計(jì)量的應(yīng)用,選擇外部時(shí)鐘是更好的選擇。
因此,在該代碼中選擇使用外部時(shí)鐘來配置SysTick定時(shí)器,以確保精確和穩(wěn)定的延時(shí)功能。
(4)時(shí)鐘源選擇
--------庫函數(shù)( SysTick_CLKSourceConfig(時(shí)鐘源)):
●時(shí)鐘源可選參數(shù):
SysTick_CLKSource_HCLK_Div8 (經(jīng)過8分頻的外部時(shí)鐘)
SysTick_CLKSource_HCLK (內(nèi)部時(shí)鐘)
●函數(shù)代碼如下:
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB) //經(jīng)過8分頻的外部時(shí)鐘
#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004) //內(nèi)部時(shí)鐘
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
((SOURCE) == SysTick_CLKSource_HCLK_Div8))
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) //時(shí)鐘源選擇庫函數(shù)
{
/* Check the parameters */
assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
{
SysTick->CTRL |= SysTick_CLKSource_HCLK;
}
else
{
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
}
}
--------寄存器
SysTick->CTRL &=~(1<<2); //選擇外部時(shí)鐘,必須清零默認(rèn)是1內(nèi)核時(shí)鐘
SysTick->CTRL |=(1<<2); //選擇內(nèi)核時(shí)鐘。
(4)延時(shí)范圍
●如系統(tǒng)時(shí)鐘頻率為72MHz,經(jīng)過8分頻后為9MHz。1s的時(shí)鐘周期個(gè)數(shù)為9000 000,1ms的時(shí)鐘周期個(gè)數(shù)為9000,1us的時(shí)鐘周期個(gè)數(shù)為9。
●VAL寄存器以及LOAD寄存器都是24位的,它的最大值是1111 1111 1111 1111 1111 1111,轉(zhuǎn)化乘十進(jìn)制后是16777215。即裝載的最大十周周期個(gè)數(shù)為16777215。
●秒級(jí)別的定時(shí)器,一次最大定時(shí)時(shí)長為:16777215 / 9000000 s。
●毫秒級(jí)別的定時(shí)器,一次最大的定時(shí)時(shí)長16777215/9000 ms,也就是1864.135毫秒,由于對(duì)于毫秒只能取整,也就是1864毫秒。
●微秒級(jí)別的定時(shí)器,一次最大定時(shí)時(shí)長是16777215/9=1864135 us。
這就是Systick定時(shí)器循環(huán)一次所能達(dá)到的最大定時(shí)時(shí)長。也就是裝載值的最大范圍。當(dāng)然也可以通過循環(huán)嵌套來實(shí)現(xiàn)更長時(shí)間的定時(shí)。
五、SysTick兩種功能
(1)查詢方式延時(shí)功能:
只需要定時(shí)器工作一個(gè)周期,也就是從重裝載值減到0的一個(gè)過程,執(zhí)行一次后需要關(guān)閉定時(shí)器,不然它還會(huì)不停的從重裝載值減到0然后又從重裝載值減到0無限循環(huán)。
實(shí)現(xiàn)功能:實(shí)現(xiàn)us、ms級(jí)別的延時(shí)函數(shù)。
偽代碼:
實(shí)現(xiàn)系統(tǒng)的us延時(shí)(參數(shù))
{
1.選擇時(shí)鐘 建議選擇經(jīng)過8分頻后的外部時(shí)鐘。
2.寫入重裝載值,設(shè)為預(yù)期值-1。
3.禁止中斷。
4.清空計(jì)數(shù)器。
5.使能計(jì)數(shù)器。
6.等待時(shí)間到達(dá),等待標(biāo)志位置1。
7.關(guān)閉計(jì)數(shù)器。
8.清空計(jì)數(shù)器。
}
具體代碼:
// uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
void delay_init()
{
SysTick->CTRL &=~(1<<2); //1.選擇外部時(shí)鐘,必須清零。默認(rèn)是1,為內(nèi)核時(shí)鐘。
//SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); // 1.選擇外部時(shí)鐘 HCLK/8
s_fac_num=SystemCoreClock/8; //選擇的經(jīng)過8分頻的外部時(shí)鐘,所以要將系統(tǒng)時(shí)鐘72Mhz/8。此時(shí)頻率為9MHz。1s震動(dòng)9 000 000 次。
us_fac_num=Clock_Div8_after/1000000; //1us 震動(dòng)9次。1s=1000 000 us.
ms_fac_num=(u16)fac_us*1000; //1個(gè)ms需要的systick時(shí)鐘數(shù) 。
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*us_fac_num-1; //2.寫入裝載值
SysTick->CTRL &=~(0x01 <<1); //3.禁止中斷
SysTick->VAL=0x00; //4.清空計(jì)數(shù)器(當(dāng)前值)這里大家一定要注意,必須使得當(dāng)前寄存器的值VAL等于0! SysTick->VAL = (0x00);只有當(dāng)VAL值為0時(shí),計(jì)數(shù)器自動(dòng)重載RELOAD。下面同理。
SysTick->CTRL |=(0x01<<0); //5.使能計(jì)數(shù)器,開始倒數(shù)。
while( (SysTick->CTRL&(1<<16)) ==0);//6.等待時(shí)間到達(dá)
SysTick->CTRL&=~(0x01<<0); //7.關(guān)閉計(jì)數(shù)器
SysTick->VAL =0X00; //8.清空計(jì)數(shù)器(當(dāng)前值)
}
void delay_ms(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*ms_fac_num-1; //2.寫入裝載值
SysTick->CTRL &=~(0x01 <<1); //3.禁止中斷
SysTick->VAL=0x00; //4.清空計(jì)數(shù)器(當(dāng)前值)這里大家一定要注意,必須使得當(dāng)前寄存器的值VAL等于0! SysTick->VAL = (0x00);只有當(dāng)VAL值為0時(shí),計(jì)數(shù)器自動(dòng)重載RELOAD。下面同理。
SysTick->CTRL |=(0x01<<0); //5.使能計(jì)數(shù)器,開始倒數(shù)。
while( (SysTick->CTRL&(1<<16)) ==0);//6.等待時(shí)間到達(dá)
SysTick->CTRL&=~(0x01<<0); //7.關(guān)閉計(jì)數(shù)器
SysTick->VAL =0X00; //8.清空計(jì)數(shù)器(當(dāng)前值)
}
(2)中斷功能:
利用中斷,一定時(shí)間進(jìn)一次中斷,以此來實(shí)現(xiàn)一個(gè)時(shí)間片輪詢的操作方式。這時(shí)候,就需要計(jì)數(shù)器一直計(jì)數(shù)了,所以不能計(jì)數(shù)完成后就關(guān)閉計(jì)數(shù)器了。
實(shí)現(xiàn)功能:每過一次設(shè)定的ms發(fā)送一次’123456’。
偽代碼:
系統(tǒng)滴答的初始化
{
1.選擇外部滴答的時(shí)鐘源。
2.配置系統(tǒng)滴答的重裝載值,設(shè)為預(yù)期值-1。
3.使能中斷。
4.當(dāng)前值清零--清空計(jì)數(shù)器。
5.設(shè)置優(yōu)先級(jí)。
6.使能NVIC響應(yīng)。
7.使能計(jì)數(shù)器。
}
中斷服務(wù)函數(shù)
{
1.檢測標(biāo)志與清除標(biāo)志;
2.執(zhí)行操作。
}
具體代碼:
#include "SysTick.h"
u16 SysTick_us;
u16 SysTick_ms;
/*******************************
函數(shù)名:SysTick_Init
函數(shù)功能:初始化系統(tǒng)滴答,選擇外部時(shí)鐘
函數(shù)形參:u32 sysclk 系統(tǒng)時(shí)鐘72(MHZ)
函數(shù)返回值:void
備注:開啟1ms中斷
********************************/
void SysTick_ms_Init(u32 nus) //72HZ
{
SysTick->CTRL &=~(1<<2); //1.選擇外部時(shí)鐘,必須清零。默認(rèn)是1,為內(nèi)核時(shí)鐘。
SysTick_s=SystemCoreClock/8; //9000 000 1s //外部時(shí)鐘8分頻
SysTick_us=SysTick_s/1000 000; //9 1us
SysTick_ms=SysTick_s/1000; //9 000 1ms
SysTick->LOAD = nus*SysTick_ms-1;//2.重裝載值9000-1
SysTick->CTRL |=(0x01<<1); //3.使能中斷 SysTick倒數(shù)計(jì)數(shù)到0時(shí)產(chǎn)生SysTick異常(中斷)請求 */
SysTick->VAL=0; //4.清空計(jì)數(shù)器,清標(biāo)志位
NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(7-2,1,2)); // 5.設(shè)置中斷優(yōu)先級(jí)
NVIC_EnableIRQ(SysTick_IRQn); //6.使能NVIC響應(yīng)
SysTick->CTRL |=1<<0; //7.使能計(jì)數(shù)器
/* 步驟5、6也可以用結(jié)構(gòu)體來配置優(yōu)先級(jí)以及使能NVIC響應(yīng)。
NVIC_InitTypeDef NVIC_InitStructure; //結(jié)構(gòu)體重命名
NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn; //選擇通道(要中斷的對(duì)象)
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //設(shè)置搶占優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //設(shè)置響應(yīng)優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道使能
NVIC_Init(&NVIC_InitStructure); //根據(jù)以上參數(shù)初始化NVIC寄存器
*/
}
void SysTick_Handler(void)
{
if((SysTick->CTRL & 0x1 << 16))//檢測標(biāo)志位,也是清除標(biāo)志位
{
SysTick->VAL=0; //清空計(jì)數(shù)器,清標(biāo)志位
printf("123456\r\n");
}
}
主函數(shù):文章來源:http://www.zghlxwxcb.cn/news/detail-808454.html
int main()
{
NVIC_SetPriorityGrouping(7-2); //設(shè)置優(yōu)先級(jí)分組。搶占2bit,響應(yīng)2bit。
SysTick_ms_Init(1); //實(shí)現(xiàn)1ms打印一次'123456'
}
六、附錄:
上述函數(shù)中,為什么SysTick的時(shí)鐘頻率需要經(jīng)過8分頻系統(tǒng)時(shí)鐘?
答:因?yàn)樵跁r(shí)鐘樹框圖中,Cortex系統(tǒng)時(shí)鐘需要系統(tǒng)時(shí)鐘經(jīng)過8分頻。文章來源地址http://www.zghlxwxcb.cn/news/detail-808454.html
到了這里,關(guān)于超詳細(xì)!必看??!STM32--系統(tǒng)滴答SysTick的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!