前言
本篇文章將給大家講解一下SYSTICK滴答定時(shí)器,以及講解使用滴答定時(shí)器來實(shí)現(xiàn)高精度延時(shí)功能的代碼。
一、SYSTick定時(shí)器介紹
SysTick定時(shí)器是嵌入式系統(tǒng)中常見的一個(gè)系統(tǒng)定時(shí)器,在ARM Cortex-M微控制器中廣泛使用。下面是關(guān)于SysTick定時(shí)器的一些介紹:
用途: SysTick定時(shí)器通常被用作操作系統(tǒng)的時(shí)鐘節(jié)拍(Tick)或者作為基本的定時(shí)器來執(zhí)行周期性的任務(wù)。它可以提供一個(gè)精確的時(shí)間基準(zhǔn),用于定時(shí)器中斷、延時(shí)函數(shù)的實(shí)現(xiàn)以及系統(tǒng)的時(shí)間管理。
定時(shí)器類型: SysTick定時(shí)器是一個(gè)24位向下計(jì)數(shù)器。它可以在一個(gè)范圍內(nèi)計(jì)數(shù)從最大值向0的時(shí)鐘周期,然后在達(dá)到0時(shí)重新裝載計(jì)數(shù)值,并觸發(fā)一個(gè)中斷(如果已使能)。
配置: 在STM32微控制器中,SysTick定時(shí)器可以通過設(shè)置相關(guān)的寄存器來配置。這些寄存器包括:
STK_CTRL:控制寄存器,用于使能或禁用SysTick定時(shí)器,選擇時(shí)鐘源和設(shè)置中斷使能。
STK_LOAD:裝載寄存器,用于設(shè)置初始的計(jì)數(shù)值。
STK_VAL:當(dāng)前值寄存器,用于讀取當(dāng)前的計(jì)數(shù)值。
STK_CALIB:校準(zhǔn)寄存器,用于存儲(chǔ)SysTick定時(shí)器的校準(zhǔn)值。
時(shí)鐘源: SysTick定時(shí)器的時(shí)鐘源可以選擇為外部時(shí)鐘或者系統(tǒng)時(shí)鐘的一個(gè)分頻。通常情況下,它與系統(tǒng)時(shí)鐘同步,但也可以使用外部時(shí)鐘來提供更靈活的配置選項(xiàng)。
中斷: SysTick定時(shí)器可以在計(jì)數(shù)器溢出時(shí)觸發(fā)中斷。這種中斷通常被用來實(shí)現(xiàn)操作系統(tǒng)的時(shí)鐘節(jié)拍,或者用于周期性任務(wù)的執(zhí)行。
應(yīng)用: SysTick定時(shí)器廣泛應(yīng)用于嵌入式系統(tǒng)中,特別是在實(shí)時(shí)操作系統(tǒng)(RTOS)中用作系統(tǒng)時(shí)鐘。它可以用來實(shí)現(xiàn)延時(shí)函數(shù)、精確的定時(shí)器中斷、周期性任務(wù)的執(zhí)行以及系統(tǒng)的時(shí)間管理。
二、SYSTick定時(shí)器和其他定時(shí)器的區(qū)別
1.SYSTick定時(shí)器是CPU內(nèi)部的定時(shí)器,其他定時(shí)器是作為STM32的外部定時(shí)器。
之所以在處理器內(nèi)增加一個(gè)定時(shí)器,是為了提高軟件的可移植性。由于所有的 Cortex-M處理器都具有相同的SysTick定時(shí)器,為一種Cortex-M3/M4微控制器實(shí)現(xiàn)的OS也能適用于其他的Cortex-M3/M4微控制器
2.功能和用途:
SYSTick定時(shí)器通常用于實(shí)現(xiàn)系統(tǒng)的時(shí)間管理、時(shí)鐘節(jié)拍以及簡(jiǎn)單的定時(shí)功能,如延時(shí)函數(shù)的實(shí)現(xiàn)等。
其他定時(shí)器(如TIM定時(shí)器)通常用于更復(fù)雜的定時(shí)和計(jì)時(shí)任務(wù),例如PWM輸出、捕獲/比較模式、定時(shí)觸發(fā)ADC轉(zhuǎn)換等。
3.精度:
SYSTick定時(shí)器的精度通常受限于系統(tǒng)時(shí)鐘頻率,因此在一般情況下可能比較低。
其他定時(shí)器通常具有更高的精度,并且可以通過外部時(shí)鐘源進(jìn)行精確校準(zhǔn),因此適用于需要更精確時(shí)間控制的應(yīng)用。
4.中斷處理:
SYSTick定時(shí)器通常只能產(chǎn)生一個(gè)中斷,用于系統(tǒng)的時(shí)鐘節(jié)拍或簡(jiǎn)單的定時(shí)任務(wù)。
其他定時(shí)器可以配置多個(gè)中斷觸發(fā)條件,允許更靈活的中斷處理和定時(shí)任務(wù)的執(zhí)行。
5.寄存器和配置:
SYSTick定時(shí)器只有幾個(gè)寄存器,配置相對(duì)簡(jiǎn)單。
其他定時(shí)器通常具有更多的寄存器和更復(fù)雜的配置選項(xiàng),以支持各種不同的定時(shí)和計(jì)時(shí)功能。
6.外設(shè)依賴性:
SYSTick定時(shí)器不依賴于外部器件,因?yàn)樗荂PU內(nèi)部的一個(gè)特殊功能模塊。
其他定時(shí)器通常依賴于外部時(shí)鐘源和其他外部器件(例如計(jì)數(shù)輸入、PWM輸出引腳等)。
7.優(yōu)先級(jí):
由于SYSTick定時(shí)器是CPU內(nèi)部的定時(shí)器,因此其中斷處理通常具有較高的優(yōu)先級(jí)。
其他定時(shí)器的中斷處理優(yōu)先級(jí)可能需要根據(jù)具體應(yīng)用情況進(jìn)行配置,并且可能不如SYSTick定時(shí)器的中斷處理優(yōu)先級(jí)高。
三、SYSTick定時(shí)器框圖講解
1.首先SYSTick根據(jù)處理器時(shí)鐘或者參考時(shí)鐘來減小計(jì)數(shù)
2.配置CTRL寄存器的第0位使能計(jì)數(shù)器,當(dāng)前值寄存器在每個(gè)處理器時(shí)鐘周期或參考時(shí)鐘的上升沿都會(huì)減小。若計(jì)數(shù)減至0,它會(huì)從重加載寄存器中加載數(shù)值并繼續(xù)
運(yùn)行。
3.另外一個(gè)寄存器為 SysTick 校準(zhǔn)值寄存器。它為軟件提供了校準(zhǔn)信息。由于 CMSISCore 提供了一個(gè)名為 SystemCoreClock 的軟件變量(CMSIS 1.2及之后版本可用,CMSIS 1.1或之前版本則使用變量 SystemFrequency),因此它就未使用SysTick 校準(zhǔn)值寄存器。系統(tǒng)初始化函數(shù) SystemInit()函數(shù)設(shè)置了該變量,而且每次系統(tǒng)時(shí)鐘配置改變時(shí)都要對(duì)其進(jìn)行更新這種軟件手段比利用SysTick 校準(zhǔn)值寄存器的硬件方式更靈活。
四、HAL庫(kù)中SYSTick配置代碼講解
滴答定時(shí)器配置代碼:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
下面是對(duì)這段代碼的配置流程的講解:
1.參數(shù)檢查:
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
這一部分首先檢查傳入的 ticks 參數(shù)是否超過了SysTick定時(shí)器的重裝載寄存器(LOAD寄存器)的最大值。如果超過了,說明無(wú)法設(shè)置這么大的重載值,函數(shù)返回1表示配置失敗。否則,繼續(xù)執(zhí)行后續(xù)的配置步驟。
2.設(shè)置重載寄存器:
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
這一行代碼設(shè)置SysTick定時(shí)器的重載寄存器,確定計(jì)數(shù)器計(jì)數(shù)到多少時(shí)觸發(fā)一次SysTick中斷。ticks - 1 是因?yàn)橛?jì)數(shù)器是從零開始計(jì)數(shù)的。
3.設(shè)置中斷優(yōu)先級(jí):
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
這里設(shè)置了SysTick定時(shí)器的中斷優(yōu)先級(jí)。NVIC_SetPriority 是一個(gè)用于設(shè)置中斷優(yōu)先級(jí)的CMSIS(Cortex Microcontroller Software Interface Standard)函數(shù)。__NVIC_PRIO_BITS 表示中斷優(yōu)先級(jí)位的數(shù)量,通常由硬件定義。這里將SysTick中斷的優(yōu)先級(jí)設(shè)置為最低,即最高數(shù)值。
4.清零計(jì)數(shù)器寄存器:
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
這一行代碼清零SysTick定時(shí)器的計(jì)數(shù)器寄存器,確保計(jì)數(shù)器從零開始計(jì)數(shù)。
5.配置并啟用SysTick定時(shí)器:
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
這一行代碼配置并啟用SysTick定時(shí)器。具體配置包括:
SysTick_CTRL_CLKSOURCE_Msk:選擇SysTick定時(shí)器的時(shí)鐘源,通常選擇處理器時(shí)鐘。
SysTick_CTRL_TICKINT_Msk:使能SysTick定時(shí)器中斷。
SysTick_CTRL_ENABLE_Msk:?jiǎn)⒂肧ysTick定時(shí)器。
返回配置結(jié)果:
return (0UL); /* Function successful */
如果上述配置步驟都成功執(zhí)行,函數(shù)返回0,表示配置成功。
五、SYSTick實(shí)現(xiàn)高精度延時(shí)
創(chuàng)建systick.c和systick.h來管理高精度延時(shí)的代碼。
systick.c
#include "systick.h"
//us級(jí)延時(shí)
void udelay(int us)
{
uint32_t told = SysTick->VAL;
uint32_t tnow;
uint32_t load = SysTick->LOAD;
/* LOAD+1個(gè)時(shí)鐘對(duì)應(yīng)1ms
* n us對(duì)應(yīng) n*(load+1)/1000個(gè)時(shí)鐘
*/
uint32_t ticks = us*(load+1)/1000;
uint32_t cnt = 0;
while (1)
{
tnow = SysTick->VAL;
if (told >= tnow)
cnt += told - tnow;
else
cnt += told + load + 1 - tnow;
told = tnow;
if (cnt >= ticks)
break;
}
}
//ms級(jí)延時(shí)
void mdelay(int ms)
{
for (int i = 0; i < ms; i++)
udelay(1000);
}
//獲取系統(tǒng)上電到現(xiàn)在經(jīng)過了多少ns
uint64_t system_get_ns(void)
{
uint64_t ns = HAL_GetTick(); /* ms */
ns = ns*1000000;
uint32_t tnow = SysTick->VAL;
uint32_t load = SysTick->LOAD;
uint64_t cnt;
cnt = load+1-tnow; /* 沒有考慮tnow等于0的情況 */
ns += cnt * 1000000 / (load+1) ;
return ns;
}
systick.h
#ifndef __SYSTICK_H__
#define __SYSTICK_H__
#include "main.h"
void udelay(int us);
void mdelay(int ms);
uint64_t system_get_ns(void);
#endif
-
udelay(int us)
這個(gè)函數(shù)實(shí)現(xiàn)了微秒級(jí)延時(shí)。其原理是利用SysTick定時(shí)器進(jìn)行精確計(jì)時(shí)。首先,獲取當(dāng)前SysTick計(jì)數(shù)器的值 told,然后計(jì)算出需要延時(shí)的時(shí)鐘周期數(shù) ticks,接著在一個(gè)循環(huán)中不斷獲取當(dāng)前計(jì)數(shù)器的值 tnow,并計(jì)算經(jīng)過的時(shí)鐘周期數(shù) cnt。當(dāng)經(jīng)過的時(shí)鐘周期數(shù)達(dá)到了延時(shí)所需的時(shí)鐘周期數(shù) ticks 時(shí),跳出循環(huán),延時(shí)結(jié)束。 -
mdelay(int ms)
這個(gè)函數(shù)實(shí)現(xiàn)了毫秒級(jí)延時(shí),它通過多次調(diào)用微秒級(jí)延時(shí)函數(shù)來實(shí)現(xiàn)。每次調(diào)用 udelay(1000) 即相當(dāng)于延時(shí)了1毫秒。 -
system_get_ns(void)
這個(gè)函數(shù)用于獲取系統(tǒng)上電到當(dāng)前時(shí)刻經(jīng)過的納秒數(shù)。首先,獲取系統(tǒng)運(yùn)行時(shí)間的毫秒數(shù) ns,然后通過當(dāng)前SysTick計(jì)數(shù)器的值 tnow 和 SysTick加載值 load 計(jì)算出當(dāng)前經(jīng)過的時(shí)鐘周期數(shù) cnt,進(jìn)而將其轉(zhuǎn)換為納秒數(shù)并加到系統(tǒng)運(yùn)行時(shí)間上,最終返回總的納秒數(shù)。文章來源:http://www.zghlxwxcb.cn/news/detail-836407.html
總結(jié)
本篇文章主要講解了SYSTick的概念,寄存器配置和使用,并且使用SYSTick實(shí)現(xiàn)了高精度延時(shí),大家可以自己寫代碼實(shí)驗(yàn)驗(yàn)證一下正確性。文章來源地址http://www.zghlxwxcb.cn/news/detail-836407.html
到了這里,關(guān)于STM32 SYSTick高精度延時(shí)功能代碼實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!