SysTick系統(tǒng)定時(shí)器是屬于CM3內(nèi)核中的一個(gè)外設(shè),內(nèi)嵌在NVIC(嵌套向量中斷控制器,控制整個(gè)芯片中斷相關(guān)的功能,它與內(nèi)核緊密藕合,是內(nèi)核中的一個(gè)外設(shè))中。系統(tǒng)定時(shí)器是一個(gè)24位的向下遞減的計(jì)數(shù)器,計(jì)數(shù)器每計(jì)數(shù)一次的時(shí)間為1/SYSCLK,一般我們?cè)O(shè)置系統(tǒng)時(shí)鐘SYSCLK為72MHZ,當(dāng)重裝載數(shù)值寄存器的值遞減為0時(shí),系統(tǒng)定時(shí)器就產(chǎn)生一次中斷,以此循環(huán)往返。
因?yàn)镾ysTick是屬于CM3內(nèi)核的外設(shè),所以所有基于CM3內(nèi)核的單片機(jī)都具有這個(gè)系統(tǒng)定時(shí)器,這使得軟件在CM3單片機(jī)中可以很容易被移植。系統(tǒng)定時(shí)器一般用于操作系統(tǒng),用于產(chǎn)生時(shí)基,維持操作系統(tǒng)的心跳。
一、SysTick寄存器介紹
SysTick系統(tǒng)定時(shí)器中有4個(gè)寄存器,分別是:
CTRL——SysTick控制及狀態(tài)寄存器
LOAD——SysTick重裝載數(shù)值寄存器
VAL——SysTick當(dāng)前數(shù)值寄存器
CALIB——SysTick校準(zhǔn)數(shù)值寄存器
在使用SysTick產(chǎn)生定時(shí)的時(shí)候,只需要配置前3個(gè)寄存器,最后一個(gè)校準(zhǔn)寄存器不需要使用。
二、SysTick定時(shí)實(shí)驗(yàn)
創(chuàng)建兩個(gè)文件bsp_SysTick.c和bsp_SysTick.h用來存放SysTick驅(qū)動(dòng)程序及相關(guān)宏定義,中斷服務(wù)函數(shù)放在stm32f10x_it.h中。要點(diǎn)在于1)設(shè)置重裝載寄存器的值;2)清楚當(dāng)前數(shù)值寄存器的值;3)配置控制與狀態(tài)寄存器。
1、SysTick配置庫函數(shù)
代碼清單——SysTick配置庫函數(shù)
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
// 不可能的重裝載值,超出范圍
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) {
return (1UL);
}
// 設(shè)置重裝載寄存器
SysTick->LOAD = (uint32_t)(ticks - 1UL);
// 設(shè)置中斷優(yōu)先級(jí)
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
// 設(shè)置當(dāng)前數(shù)值寄存器
SysTick->VAL = 0UL;
// 設(shè)置系統(tǒng)定時(shí)器的時(shí)鐘源為 AHBCLK=72M
// 使能系統(tǒng)定時(shí)器中斷
// 使能定時(shí)器
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0UL);
}
用固件庫編程時(shí)我們只需要調(diào)用庫函數(shù)SysTick_Config()即可,形參ticks用來設(shè)置重裝載寄存器的值,再大不超過重裝載寄存器的值2^24,當(dāng)重裝載寄存器的值遞減到0的時(shí)候產(chǎn)生中斷,然后重裝載寄存器的值又重新裝載往下遞減計(jì)數(shù),以此循環(huán)往復(fù)。隨后設(shè)置好中斷優(yōu)先級(jí),最后配置系統(tǒng)定時(shí)器的時(shí)鐘等于AHBCLK=72MHZ,使能定時(shí)器和定時(shí)器中斷,這樣系統(tǒng)定時(shí)器就配置好了。
SysTick_Config()庫函數(shù)主要配置了SysTick中的3個(gè)寄存器:LOAD、VAL和CTRL。
2、配置SysTick中斷優(yōu)先級(jí)
SysTick_Config()庫函數(shù)還調(diào)用了固件庫NVIC_SetPriority()來配置系統(tǒng)定時(shí)器的中斷優(yōu)先級(jí),該函數(shù)也在core_m3.h中定義。
代碼清單——配置SysTick中斷優(yōu)先級(jí)
_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)IRQn < 0)
{
SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] =
(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
else
{
NVIC->IP[((uint32_t)(int32_t)IRQn)] =
(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
}
函數(shù)首先判斷形參IRQn的大小,如果小于0,則表示這個(gè)是系統(tǒng)異常,系統(tǒng)異常的優(yōu)先級(jí)由內(nèi)核外設(shè)SCB的寄存器SHPRx控制;如果大于0,則是外部中斷,外部中斷的優(yōu)先級(jí)由內(nèi)核外設(shè)NVIC中的IPx寄存器控制。
因?yàn)镾ysTick屬于內(nèi)核外設(shè) ,與普通外設(shè)的中斷優(yōu)先級(jí)有些區(qū)別,并沒有 搶占優(yōu)先級(jí)和子優(yōu)先級(jí)的說法。在STM32F103中,內(nèi)核外設(shè)的中斷優(yōu)先級(jí)由內(nèi)核SCB這個(gè)外設(shè)的寄存器SHPRx(x=1~3)來配置。
SPRH1~SPRH3是一個(gè)32位的寄存器,但是只能通過字節(jié)訪問,每8個(gè)字段控制一個(gè)內(nèi)核外設(shè)的中斷優(yōu)先級(jí)的配置。STM32F103中,只有位7~位3這高4位有效,低4位沒有用到,所以內(nèi)核外設(shè)的中斷優(yōu)先級(jí)可編程為0~15,只有16個(gè)編程優(yōu)先級(jí),數(shù)值越小優(yōu)先級(jí)越高。
在系統(tǒng)定時(shí)器中,配置優(yōu)先級(jí)為(1UL << __NVIC_PRIO_BITS) - 1UL),其中宏
__NVIC_PRIO_BITS 為 4,那計(jì)算結(jié)果就等于 15,可以看出系統(tǒng)定時(shí)器此時(shí)設(shè)置的優(yōu)先級(jí)
在內(nèi)核外設(shè)中是最低的,如果要修改優(yōu)先級(jí)則修改這個(gè)值即可,范圍為:0~15。
設(shè)置系統(tǒng)定時(shí)器中斷優(yōu)先級(jí)
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
以上是內(nèi)核的外設(shè)優(yōu)先級(jí)設(shè)置,如果同時(shí)使用了SysTick和片上外設(shè)呢 ?
比如配置一個(gè)外設(shè)的中斷優(yōu)先級(jí)分組為2,搶占優(yōu)先級(jí)為1,子優(yōu)先級(jí)為1,SysTick的優(yōu)先級(jí)為固件庫默認(rèn)配置的15。當(dāng)我們比較內(nèi)核外設(shè)和片上外設(shè)的時(shí)候,我們只需要抓住NVIC的中斷優(yōu)先級(jí)分組不僅對(duì)片上外設(shè)有效,同樣對(duì)內(nèi)核的外設(shè)也有效,把SysTick的優(yōu)先級(jí)15轉(zhuǎn)換成二進(jìn)制就是1111(0b),又因?yàn)镹VIC的優(yōu)先級(jí)分組為2,那么前兩位的11(0b)也是3,后兩位也是3,無論從搶占還是子優(yōu)先級(jí)都比我們?cè)O(shè)定的外設(shè)的優(yōu)先級(jí)低。如果2個(gè)軟件優(yōu)先級(jí)配置成一樣,那就比較硬件編號(hào),編號(hào)越小,優(yōu)先級(jí)越高。
3、SysTick初始化函數(shù)
代碼清單——SysTick初始化
/**
* @brief 啟動(dòng)系統(tǒng)滴答定時(shí)器 SysTick
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms 中斷一次
* SystemFrequency / 100000 10us 中斷一次
* SystemFrequency / 1000000 1us 中斷一次
*/
if (SysTick_Config(SystemCoreClock / 100000)) {
/* Capture error */
while (1);
}
}
SysTick初始化函數(shù)由用戶編寫,里面的SysTick_Config()固件庫函數(shù),通過設(shè)置該固件庫的形參,就決定了系統(tǒng)定時(shí)器經(jīng)過多少時(shí)間產(chǎn)生一次中斷。
4、SysTick_Config中斷時(shí)間的計(jì)算
SysTick 定時(shí)器的計(jì)數(shù)器是向下遞減計(jì)數(shù)的,計(jì)數(shù)一次的時(shí)間 T (DEC) =1/CLK (AHB) ,當(dāng)重裝載寄存器中的值 VALUE (LOAD) 減到 0 的時(shí)候,產(chǎn)生中斷,可知中斷一次的時(shí)間T (INT) =VALUE (LOAD) * T (DEC) = VALUE (LOAD) /CLK (AHB) , 其 中 CLK (AHB) =72MHZ 。 如 果 設(shè) 置VALUE (LOAD) 為 72,那中斷一次的時(shí)間 T (INT) =72/72M=1us。不過 1us 的中斷沒啥意義,整個(gè)程序的重心都花在進(jìn)出中斷上了,根本沒有時(shí)間處理其他的任務(wù)。
SysTick_Config(SystemCoreClock / 100000))
SysTick_Config()的形我們配置為 SystemCoreClock / 100000=72M/100000=720,從剛剛分析我們知道這個(gè)形參的值最終是寫到重裝載寄存器 LOAD 中的,從而可知我們現(xiàn)在把SysTick 定時(shí)器中斷一次的時(shí)間 T (INT) =720/72M=10us。
5、SysTick定時(shí)時(shí)間的計(jì)算
設(shè)置好T(INT)后,可以設(shè)置一個(gè)變量t,用來記錄進(jìn)入中斷的次數(shù),那么用變量t乘以中斷的時(shí)間T(INT),就可以計(jì)算出需要定時(shí)的時(shí)間。
6、SysTick定時(shí)函數(shù)
定義一個(gè)微妙級(jí)別的延時(shí)函數(shù),形參為nTime,用這個(gè)形參乘以中斷時(shí)間T(INT)就得出我們需要的延時(shí)時(shí)間。
代碼清單——SysTick定時(shí)函數(shù)
/**
* @brief us 延時(shí)程序,10us 為一個(gè)單位
* @param
* @arg nTime: Delay_us( 1 ) 則實(shí)現(xiàn)的延時(shí)為 1 * 10us = 10us
* @retval 無
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
while (TimingDelay != 0);
}
函數(shù)Delay_us中我們等待TimingDelay為0,當(dāng)TimingDelay為0時(shí)表示延時(shí)時(shí)間到。即SysTick每進(jìn)行一次中斷(10us),TimingDelay遞減一次。
7、SysTick中斷服務(wù)函數(shù)
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
中斷復(fù)位函數(shù)調(diào)用了另外一個(gè)函數(shù) TimingDelay_Decrement(),如下
* @attention 在 SysTick 中斷函數(shù) SysTick_Handler()調(diào)用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00) {
TimingDelay--;
TimingDelay的值等于延時(shí)函數(shù)中 傳進(jìn)去的nTime的值,比如nTime=100 000,則延時(shí)的時(shí)間等于100 000x10us=1s。
8、main函數(shù)
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置 SysTick 為 10us 中斷一次,時(shí)間到后觸發(fā)定時(shí)中斷,
*進(jìn)入 stm32fxx_it.c 文件的 SysTick_Handler 處理,通過數(shù)中斷次數(shù)計(jì)時(shí)
*/
SysTick_Init();
while (1)
{
LED_ON;
Delay_us(100000); // 10000 * 10us = 1000ms
LED2_ON;
Delay_us(100000); // 10000 * 10us = 1000ms
LED3_ON;
Delay_us(100000); // 10000 * 10us = 1000ms
}
}
三、另一種更簡(jiǎn)潔的定時(shí)編程
SysTick的counter從reloader的值往下遞減到0的時(shí)候,CTRL寄存器的位16:countflag會(huì)置1,且讀取該位的值可清0,所以可以使用軟件查詢的方法實(shí)現(xiàn)延時(shí)。
代碼清單——SysTick微秒級(jí)延時(shí)
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for (i=0; i // 當(dāng)計(jì)數(shù)器的值減小到 0 的時(shí)候,CRTL 寄存器的位 16 會(huì)置 1 while ( !((SysTick->CTRL)&(1<<16)) ); } // 關(guān)閉 SysTick 定時(shí)器 SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk; } 代碼清單——SysTick毫秒級(jí)延時(shí) void SysTick_Delay_Ms( __IO uint32_t ms) { uint32_t i; SysTick_Config(SystemCoreClock/1000); for (i=0; i // 當(dāng)計(jì)數(shù)器的值減小到 0 的時(shí)候,CRTL 寄存器的位 16 會(huì)置 1 // 當(dāng)置 1 時(shí),讀取該位會(huì)清 0 while ( !((SysTick->CTRL)&(1<<16)) ); } // 關(guān)閉 SysTick 定時(shí)器 SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk; } 代碼清單——SysTick配置函數(shù) // 這個(gè) 固件庫函數(shù) 在 core_cm3.h 中 static __INLINE uint32_t SysTick_Config(uint32_t ticks) { // reload 寄存器為 24bit,最大值為 2^24 if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); // 配置 reload 寄存器的初始值 SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; // 配置中斷優(yōu)先級(jí)為 1<<4 -1 = 15,優(yōu)先級(jí)為最低 NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); // 配置 counter 計(jì)數(shù)器的值 SysTick->VAL = 0; // 配置 systick 的時(shí)鐘為 72M // 使能中斷 // 使能 systick SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; return (0); }
上一篇:問題:stm32 SysTick_Handler()使用
下一篇:使用SysTick的普通計(jì)數(shù)模式對(duì)延遲進(jìn)行管理
推薦閱讀
史海拾趣
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 神經(jīng)形態(tài)芯片可能是革新機(jī)器人實(shí)時(shí)電機(jī)控制的未來
- 從三個(gè)方面理解ARM嵌入式系統(tǒng)
- 自動(dòng)報(bào)警 基于MCU的家庭防盜報(bào)警系統(tǒng)的設(shè)計(jì)
- 存儲(chǔ)控制器及其訪問外設(shè)的原理
- 基于51系列單片機(jī)的智能照明控制系統(tǒng)設(shè)計(jì)方案
- 基于STM32的四旋翼飛行器控制系統(tǒng)
- 單片機(jī)應(yīng)用編程技巧解析
- 基于89C52的教室智能節(jié)能照明系統(tǒng)設(shè)計(jì)
- 一種新型的雨量光照傳感器的設(shè)計(jì)
- RISC-V人才該怎么培養(yǎng)?專家這樣說
- 割草機(jī)器人,四大流派的巔峰之戰(zhàn)
- 車載顯示迎來三大革命丨“形態(tài)”革命
- 什么是“CDC+空懸”?
- 汽車電子信息安全:如何有效保護(hù)硬件Debug口?
- 新能源汽車核心技術(shù)之“大三電”、“小三電”
- 芯原如何推動(dòng)RISC-V嵌入式軟件人才發(fā)展?
- Arm 技術(shù)助力《國(guó)家地理》探險(xiǎn)家繪制地球海洋圖景
- Arm SME2 技術(shù)加速安卓 AI 升級(jí),驅(qū)動(dòng)移動(dòng)應(yīng)用下一代功能革新
- VGA接口定義、功能用途和種類
- 有獎(jiǎng)電源小課堂 | PI 1250V高壓氮化鎵芯片
- 逛村田在線云展廳,了解通信、移動(dòng)、工業(yè)+環(huán)境、健康四大領(lǐng)域的應(yīng)用干貨!
- 答題贏好禮 | TDK專題報(bào)道只等你來(第3期)
- 免費(fèi)申請(qǐng) | SFH 4713B紅外LED樣片,體驗(yàn)革新性IR:6技術(shù)
- ST有獎(jiǎng)直播 | 75V降壓控制器和隔離降壓方案
- 【搶樓贏禮】聊聊“我眼中的ADI實(shí)驗(yàn)室電路”
- ADI有獎(jiǎng)下載活動(dòng)之19:ADI可編程邏輯控制器(PLC)解決方案(更新版)
- 免費(fèi)申請(qǐng)測(cè)評(píng) | Sipeed MAix BiT AIoT 開發(fā)套件,搭載K210、屏幕和攝像頭
- 有獎(jiǎng)直播|ADI電機(jī)控制解決方案
- 汽車零部件發(fā)動(dòng)機(jī)外殼柔性浮動(dòng)去毛刺主軸加工應(yīng)用
- AI技術(shù)十年進(jìn)階:一段算法能力演進(jìn)的歷史
- 2021年上半年,張江人工智能產(chǎn)業(yè)進(jìn)一步“擴(kuò)圈”
- 協(xié)作機(jī)器人未來新產(chǎn)品、新技術(shù)及發(fā)展趨勢(shì)
- 威視芯首顆智能高清電視SoC 回片點(diǎn)亮,四季度量產(chǎn)
- 安森美半導(dǎo)體通過短期股東權(quán)利計(jì)劃
- 5G商用一周年,你覺得變化大嗎?
- 發(fā)起電池革命!寧德時(shí)代聯(lián)手特斯拉將生產(chǎn)百萬英里電池
- 分析師:5G產(chǎn)業(yè)不能沒有華為
- 外媒:5G光學(xué)濾波器供不應(yīng)求