RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第5章 跳動(dòng)的心臟-Systick

嵌入式大雜燴 ? 來(lái)源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2023-05-10 09:00 ? 次閱讀

開(kāi)發(fā)環(huán)境:

MDK:Keil 5.30

開(kāi)發(fā)板:GD32F207I-EVAL

MCU:GD32F207IK

Cortex-M的內(nèi)核中包含Systick定時(shí)器了,只要是Cortex-M系列的MCU就會(huì)有Systick,因此這是通用的,下面詳細(xì)分析。

1 Systick工作原理分析

SysTick 定時(shí)器被捆綁在 NVIC 中,用于產(chǎn)生 SysTick 異常(異常號(hào) :15)。在以前,操作系統(tǒng)和所有使用了時(shí)基的系統(tǒng)都必須有一個(gè)硬件定時(shí)器來(lái)產(chǎn)生需要的“滴答”中斷,作為整個(gè)系統(tǒng)的時(shí)基。滴答中斷對(duì)操作系統(tǒng)尤其重要。例如,操作系統(tǒng)可以為多個(gè)任務(wù)分配不同數(shù)目的時(shí)間片,確保沒(méi)有一個(gè)任務(wù)能霸占系統(tǒng) ;或者將每個(gè)定時(shí)器周期的某個(gè)時(shí)間范圍賜予特定的任務(wù)等,操作系統(tǒng)提供的各種定時(shí)功能都與這個(gè)滴答定時(shí)器有關(guān)。因此,需要一個(gè)定時(shí)器來(lái)產(chǎn)生周期性的中斷,而且最好還讓用戶程序不能隨意訪問(wèn)它的寄存器,以維持操作系統(tǒng)“心跳”的節(jié)律。

1683642280703y06zbdqjnq

Cortex-M3 在內(nèi)核部分包含了一個(gè)簡(jiǎn)單的定時(shí)器——SysTick。因?yàn)樗械?CM3 芯片都帶有這個(gè)定時(shí)器,軟件在不同芯片生產(chǎn)廠商的 CM3 器件間的移植工作就得以簡(jiǎn)化。該定時(shí)器的時(shí)鐘源可以是內(nèi)部時(shí)鐘(FCLK,CM3 上的自由運(yùn)行時(shí)鐘),或者是外部時(shí)鐘。不過(guò),外部時(shí)鐘的具體來(lái)源則由芯片設(shè)計(jì)者決定,因此不同產(chǎn)品之間的時(shí)鐘頻率可能大不相同。因此,需要閱讀芯片的使用手冊(cè)來(lái)確定選擇什么作為時(shí)鐘源。在 GD32 中SysTick 以 HCLK(AHB 時(shí)鐘)或 HCLK/8 作為運(yùn)行時(shí)鐘,見(jiàn)上圖。

SysTick 定時(shí)器能產(chǎn)生中斷,CM3 為它專門開(kāi)出一個(gè)異常類型,并且在向量表中有它的一席之地。它使操作系統(tǒng)和其他系統(tǒng)軟件在 CM3 器件間的移植變得簡(jiǎn)單多了,因?yàn)樵谒?CM3 產(chǎn)品間,SysTick 的處理方式都是相同的。SysTick 定時(shí)器除了能服務(wù)于操作系統(tǒng)之外,還能用于其他目的,如作為一個(gè)鬧鈴、用于測(cè)量時(shí)間等。 Systick 定時(shí)器屬于Cortex 內(nèi)核部件 ,可以參考《ARM Cortex-M3 權(quán)威指南》((英)JosephYiu 著,宋巖譯,北京航空航天大學(xué)出版社出版)來(lái)了解。

2 Systick寄存器分析

在傳統(tǒng)的嵌入式系統(tǒng)軟件按中通常實(shí)現(xiàn) Delay(N) 函數(shù)的方法為:

for(i = 0; i <= x; i ++);

x --- ;

對(duì)于GD32系列微處理器來(lái)說(shuō),執(zhí)行一條指令只有幾十個(gè) ns,進(jìn)行 for 循環(huán)時(shí),要實(shí)現(xiàn) N 毫秒的 x 值非常大,而且由于系統(tǒng)頻率的寬廣,很難計(jì)算出延時(shí) N 毫秒的精確值。針對(duì)GD32 微處理器,需要重新設(shè)計(jì)一個(gè)新的方法去實(shí)現(xiàn)該功能,以實(shí)現(xiàn)在程序中使用 Delay(N)。

Cortex-M3 的內(nèi)核中包含一個(gè) SysTick 時(shí)鐘。SysTick 為一個(gè) 24 位遞減計(jì)數(shù)器,SysTick 設(shè)定初值并使能后,每經(jīng)過(guò) 1 個(gè)系統(tǒng)時(shí)鐘周期,計(jì)數(shù)值就減 1。計(jì)數(shù)到 0 時(shí),SysTick 計(jì)數(shù)器自動(dòng)重裝初值并繼續(xù)計(jì)數(shù),同時(shí)內(nèi)部的 COUNTFLAG 標(biāo)志會(huì)置位,觸發(fā)中斷 (如果中斷使能情況下)。

在 GD32 的應(yīng)用中,使用 Cortex-M3 內(nèi)核的 SysTick 作為定時(shí)時(shí)鐘,設(shè)定每一毫秒產(chǎn)生一次中斷,在中斷處理函數(shù)里對(duì) N 減一,在Delay(N) 函數(shù)中循環(huán)檢測(cè) N 是否為 0,不為 0 則進(jìn)行循環(huán)等待;若為 0 則關(guān)閉 SysTick 時(shí)鐘,退出函數(shù)。

注: 全局變量 TimingDelay , 必須定義為 volatile 類型 , 延遲時(shí)間將不隨系統(tǒng)時(shí)鐘頻率改變。

Cortex-M3中的Systick部分內(nèi)容屬于NVIC控制部分,一共有4個(gè)寄存器,名稱和地址分別是:

  • STK_CTRL,0xE000E010--控制寄存器

1683642281331ygg5hvor5x

第0位:ENABLE,Systick 使能位

(0:關(guān)閉Systick功能;1:開(kāi)啟Systick功能)

第1位:TICKINT,Systick 中斷使能位

(0:關(guān)閉Systick中斷;1:開(kāi)啟Systick中斷)

第2位:CLKSOURCE,Systick時(shí)鐘源選擇

(0:使用HCLK/8 作為Systick時(shí)鐘;1:使用HCLK作為Systick時(shí)鐘)

第16位:COUNTFLAG,Systick計(jì)數(shù)比較標(biāo)志,如果在上次讀取本寄存器后,SysTick 已經(jīng)數(shù)到了0,則該位為1。如果讀取該位,該位將自動(dòng)清零

  • STK_LOAD, 0xE000E014--重載寄存器

1683642281747f5i5uqwxre

Systick是一個(gè)遞減的定時(shí)器,當(dāng)定時(shí)器遞減至0時(shí),重載寄存器中的值就會(huì)被重裝載,繼續(xù)開(kāi)始遞減。STK_LOAD 重載寄存器是個(gè)24位的寄存器最大計(jì)數(shù)0xFFFFFF。

  • STK_VAL, 0xE000E018--當(dāng)前值寄存器

1683642282071e7f33le3xp

也是個(gè)24位的寄存器,讀取時(shí)返回當(dāng)前倒計(jì)數(shù)的值,寫它則使之清零,同時(shí)還會(huì)清除在SysTick控制及狀態(tài)寄存器中的COUNTFLAG標(biāo)志。

  • STK_CALRB, 0xE000E01C--校準(zhǔn)值寄存器

1683642282361vwfhmxvgzx

校準(zhǔn)值寄存器提供了這樣一個(gè)解決方案:它使系統(tǒng)即使在不同的CM3產(chǎn)品上運(yùn)行,也能產(chǎn)生恒定的SysTick中斷頻率。最簡(jiǎn)單的作法就是:直接把TENMS的值寫入重裝載寄存器,這樣一來(lái),只要沒(méi)突破系統(tǒng)極限,就能做到每10ms來(lái)一次 SysTick異常。如果需要其它的SysTick異常周期,則可以根據(jù)TENMS的值加以比例計(jì)算。只不過(guò),在少數(shù)情況下, CM3芯片可能無(wú)法準(zhǔn)確地提供TENMS的值(如, CM3的校準(zhǔn)輸入信號(hào)被拉低),所以為保險(xiǎn)起見(jiàn),最好在使用TENMS前檢查器件的參考手冊(cè)。

SysTick定時(shí)器除了能服務(wù)于操作系統(tǒng)之外,還能用于其它目的:如作為一個(gè)鬧鈴,用于測(cè)量時(shí)間等。要注意的是,當(dāng)處理器在調(diào)試期間被喊停( halt)時(shí),則SysTick定時(shí)器亦將暫停運(yùn)作。

3 Systick定時(shí)器實(shí)現(xiàn)

SysTick屬于Cortex-M內(nèi)核的部分,因此其相關(guān)的定義在core_cm3.h文件中。

3.1 main文件分析

主函數(shù)如下:

/*
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{
    //systick init
    sysTick_init();
	
    /* configure LED1 GPIO port */
    led_init(LED1);

    /* configure LED2 GPIO port */
    led_init(LED2);

    /* configure LED3 GPIO port */
    led_init(LED3);

    /* configure LED4 GPIO port */
    led_init(LED4);

    while(1) 
    {
        /* turn on LED1, turn off LED4 */
        led_on(LED1);
        led_off(LED4);
        /*delay 500ms*/
        delay_ms(500);

        /* turn on LED2, turn off LED1 */
        led_on(LED2);
        led_off(LED1);
        /*delay 500ms*/
        delay_ms(500);

        /* turn on LED3, turn off LED2 */
        led_on(LED3);
        led_off(LED2);
        /*delay 500ms*/
        delay_ms(500);

        /* turn on LED4, turn off LED3 */
        led_on(LED4);
        led_off(LED3);
        /*delay 500ms*/
        delay_ms(500);
    }
}

在 main 函數(shù)中,sysTick_init和 delay_us() 這兩個(gè)函數(shù)比較陌生,它們的功能分別是配置好 SysTick 定時(shí)器和進(jìn)行精確延時(shí)。整個(gè) main 函數(shù)的流程就是初始化 LED 及SysTick 定時(shí)器之后,就進(jìn)入死循環(huán),點(diǎn)亮LED的時(shí)間為精確的 500 ms。

3.2 gd32f207i_systick_eval.c文件分析

  • 配置并啟動(dòng) SysTick

我們看一下systick_init()這個(gè)函數(shù),其功能是啟動(dòng)系統(tǒng)滴答定時(shí)器 SysTick。

/*
    brief      SysTick init
    param[in]  none
    param[out] none
    retval     none
*/
void sysTick_init(void)
{
	 /* SystemFrequency / 1000    1ms中斷一次
	  * SystemFrequency / 100000  10us中斷一次
	  * SystemFrequency / 1000000 1us中斷一次
	  */
    /* setup systick timer for 1000Hz interrupts */
    if(SysTick_Config(SystemCoreClock / 100000U)){
        /* capture error */
        while(1){
        }
    }

    // 關(guān)閉滴答定時(shí)器  
    SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;

    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

本函數(shù)實(shí)際上只是調(diào)用了 SysTick_Config() 函數(shù),它是屬于內(nèi)核層的 Cortex-M3 通用函數(shù),位于 core_cm3.h 文件中。若調(diào)用 SysTick_Config() 配置 SysTick 不成功,則進(jìn)入死循環(huán),初始化 SysTick 成功后,先關(guān)閉定時(shí)器,在需要的時(shí)候再開(kāi)啟。SysTick_Config() 函數(shù)無(wú)法在GD32 外設(shè)固件庫(kù)文件中找到其使用方法。所以我們?cè)?Keil 環(huán)境下直接跟蹤這個(gè)函數(shù)到 core_cm3.h 文件,查看函數(shù)的定義。

/** \\brief  System Tick Configuration

    The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
    Counter is in free running mode to generate periodic interrupts.

    \\param [in]  ticks  Number of ticks between two interrupts.

    \\return          0  Function succeeded.
    \\return          1  Function failed.

    \\note     When the variable __Vendor_SysTickConfig is set to 1, then the
    function SysTick_Config is not included. In this case, the file device.h
    must contain a vendor-specific implementation of this function.

 */
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */

  SysTick->LOAD  = ticks - 1;                                  /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0;                                          /* 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 (0);                                                  /* Function successful */
}

在這個(gè)函數(shù)定義的前面有關(guān)于它的注釋,如果我們不想去研究它的具體實(shí)現(xiàn),可以根據(jù)這段注釋了解函數(shù)的功能 :這個(gè)函數(shù)啟動(dòng)了 SysTick ;并把它配置為計(jì)數(shù)至 0 時(shí)引起中斷 ;輸入的參數(shù) ticks 為兩個(gè)中斷之間的脈沖數(shù),即相隔 ticks 個(gè)時(shí)鐘周期會(huì)引起一次中斷 ;配置 SysTick 成功時(shí)返回 0,出錯(cuò)時(shí)返回 1。但是,這段注釋并沒(méi)有告訴我們它把 SysTick 的時(shí)鐘設(shè)置為 AHB 時(shí)鐘還是 AHB/8,這是一個(gè)十分關(guān)鍵的問(wèn)題,于是,我們將對(duì)這個(gè)函數(shù)的具體實(shí)現(xiàn)進(jìn)行分析,與大家再分享一下如何分析底層庫(kù)函數(shù)。分析底層庫(kù)函數(shù),要有 SysTick 定時(shí)器工作分析的知識(shí)準(zhǔn)備。

  • 檢查輸入?yún)?shù)

SysTick_Config() 第 3 行代碼是檢查輸入?yún)?shù) ticks,因?yàn)?ticks 是脈沖計(jì)數(shù)值,要被保存到重載寄存器 STK_LOAD 寄存器中,再由硬件把 STK_LOAD 值加載到當(dāng)前計(jì)數(shù)值寄存器 STK_VAL 中使用,STK_LOAD 和 STK_VAL 都是 24 位的,所以當(dāng)輸入?yún)?shù) ticks 大于其可存儲(chǔ)的最大值時(shí),將由這行代碼檢查出錯(cuò)誤并返回。

  • 位指示宏及位屏蔽宏

檢查 ticks 參數(shù)沒(méi)有錯(cuò)誤后,就稍稍處理一下把 ticks-1 賦值給 STK_LOAD 寄存器,要注意的是減 1,若 STK_VAL 從 ticks?1 向下計(jì)數(shù)至 0,實(shí)際上就經(jīng)過(guò)了 ticks 個(gè)脈沖。這句賦值代碼使用了宏 SysTick_LOAD_RELOAD_Msk,與其他庫(kù)函數(shù)類似,這個(gè)宏是用來(lái)指示寄存器的特定位置或進(jìn)行位屏蔽的。

/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos         16                                             /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk         (1ul << SysTick_CTRL_COUNTFLAG_Pos)            /*!< SysTick CTRL: COUNTFLAG Mask */

#define SysTick_CTRL_CLKSOURCE_Pos          2                                             /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk         (1ul << SysTick_CTRL_CLKSOURCE_Pos)            /*!< SysTick CTRL: CLKSOURCE Mask */

#define SysTick_CTRL_TICKINT_Pos            1                                             /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk           (1ul << SysTick_CTRL_TICKINT_Pos)              /*!< SysTick CTRL: TICKINT Mask */

#define SysTick_CTRL_ENABLE_Pos             0                                             /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk            (1ul << SysTick_CTRL_ENABLE_Pos)               /*!< SysTick CTRL: ENABLE Mask */

/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos             0                                             /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos)        /*!< SysTick LOAD: RELOAD Mask */

/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos             0                                             /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk            (0xFFFFFFul << SysTick_VAL_CURRENT_Pos)        /*!< SysTick VAL: CURRENT Mask */

/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos            31                                             /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk            (1ul << SysTick_CALIB_NOREF_Pos)               /*!< SysTick CALIB: NOREF Mask */

#define SysTick_CALIB_SKEW_Pos             30                                             /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk             (1ul << SysTick_CALIB_SKEW_Pos)                /*!< SysTick CALIB: SKEW Mask */

#define SysTick_CALIB_TENMS_Pos             0                                             /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk            (0xFFFFFFul << SysTick_VAL_CURRENT_Pos)        /*!< SysTick CALIB: TENMS Mask */
/*@}*/ /* end of group CMSIS_CM3_SysTick */

其中寄存器位指示宏 :SysTick_xxx_Pos ,宏展開(kāi)后即為 xxx 在相應(yīng)寄存器中的位置,如控制 SysTick 時(shí)鐘源的 SysTick_CTRL_CLKSOURCE_Pos ,宏展開(kāi)為 2,這個(gè)寄存器位正是寄存器 STK_CTRL 中的 Bit2。

而寄存器位屏蔽宏 :SysTick_xxx_Msk,宏展開(kāi)是 xxx 的位全部置 1 后,左移SysTick_xxx_Pos 位。如控制 SysTick 時(shí)鐘源的 SysTick_CTRL_CLKSOURCE_Msk,宏展開(kāi)為“1ul << SysTick_CTRL_CLKSOURCE_Pos”, 把無(wú)符號(hào)長(zhǎng)整型數(shù)值(ul) 1 左移 2 位, 得 到 了 一 個(gè) 只 有 Bit2 :CLKSOURCE 位被置 1,其他位為 0 的數(shù)值,這樣的數(shù)值配合位操作 &(按位與)、| (按位或)可以很方便地修改寄存器的某些位。假如控制 CLKSOURCE 需 要 4 個(gè)寄存器位,這個(gè)宏就應(yīng)該被改為( 0xf ul <

  • 配置中斷向量及重置 STK_VAL 寄存器

回到 SysTick_Config() 函數(shù),接下來(lái)調(diào)用了 NVIC_SetPriority () 函數(shù)并配置了 SysTick中斷,如果想修改SysTick的優(yōu)先級(jí),也可以在外部使用 NVIC 配置 SysTick 中斷。配置好SysTick 中斷后把 STK_VAL 寄存器重新賦值為 0(在使能 SysTick 時(shí),硬件會(huì)把存儲(chǔ)在STK_LOAD 寄存器 中的 ticks 值加載給它)。

  • 配置 SysTick 時(shí)鐘為 AHB

在這段代碼最后,向 STK_CTRL 寄存器寫入了 SysTick 的控制參數(shù),配置為使用AHB 時(shí)鐘,使能計(jì)數(shù)至 0 時(shí)引起中斷,使能 SysTick。執(zhí)行了這行代碼,SysTick 就開(kāi)始運(yùn)行并進(jìn)行脈沖計(jì)數(shù)了。

若想要使用 AHB/8 作為時(shí)鐘,可以直接在SysTick_Config()函數(shù)中對(duì)SysTick->CTRL進(jìn)行修改,當(dāng)然最好自定義sysTick_init()函數(shù)中修改。

  • 使能、關(guān)閉定時(shí)器

由于調(diào)用 SysTick_Config() 函數(shù)之后,SysTick 定時(shí)器就被開(kāi)啟了,但我們?cè)诔跏蓟臅r(shí)候并不希望這樣,而是根據(jù)需要再開(kāi)啟。所以在 sysTick_init() 函數(shù)中,調(diào)用完SysTick_Config() 并配置好后,應(yīng)先把定時(shí)器關(guān)閉了。SysTick 的開(kāi)啟和關(guān)閉由寄存器STK_CTRL 的 Bit0 :ENABLE 位來(lái)控制,使用位屏蔽宏以操作寄存器的方式實(shí)現(xiàn)。

SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 使能滴答定時(shí)器
SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; // 關(guān)閉滴答定時(shí)器
  • 定時(shí)時(shí)間的計(jì)算

在調(diào)用SysTick_Config()函數(shù)時(shí),向它輸入的參數(shù)為SystemCoreClock / 100000,SystemCoreClock為定義了系統(tǒng)時(shí)鐘(SYSCLK)頻率的宏,即等于 AHB的時(shí)鐘頻率。在本書的所有例程中AHB 都是被配置為 120MHz 的,也就是這個(gè) SystemCoreClock 宏展開(kāi)為數(shù)值 12000 0000。

根據(jù)前面對(duì) SysTick_Config() 函數(shù)的介紹,它的輸入?yún)?shù)為 SysTick 將要計(jì)時(shí)的脈沖數(shù),經(jīng)過(guò) ticks 個(gè)脈沖(經(jīng)過(guò) ticks 個(gè)時(shí)鐘周期)后將觸發(fā)中斷,觸發(fā)中斷后又重新開(kāi)始計(jì)數(shù)。由此我們可以算出定時(shí)的時(shí)間,下面為計(jì)算公式 :

T=ticks×(1/f)

其中,T 為要定時(shí)的總時(shí)間 ;ticks 為 SysTick_Config() 的輸入?yún)?shù) ;1/ f 即為SysTick 使用的時(shí)鐘源的時(shí)鐘周期,f 為該時(shí)鐘源的時(shí)鐘頻率,當(dāng)時(shí)鐘源確定后為常數(shù)。

本例中使用時(shí)鐘源為 AHB 時(shí)鐘,其頻率被配置為 120 MHz。調(diào)用函數(shù)時(shí),把 ticks 賦值為 ticks=SystemFrequency / 100000 =1200,表示 1200 個(gè)時(shí)鐘周期中斷一次 ;1/f 是時(shí)鐘周期的時(shí)間,此時(shí)1/f =1/120 us,所以最終定時(shí)總時(shí)間 T=1200x(1/120),為1200 個(gè)時(shí)鐘周期,正好是 10us。

SysTick 定時(shí)器的定時(shí)時(shí)間(配置為觸發(fā)中斷,即為中斷周期)由 ticks 參數(shù)決定,最大定時(shí)周期不能超過(guò) 224 個(gè)。

  • 編寫中斷服務(wù)函數(shù)

一旦我們調(diào)用了 delay_us() 函數(shù),SysTick 定時(shí)器就被開(kāi)啟,按照設(shè)定好的定時(shí)周期遞減計(jì)數(shù),當(dāng) SysTick 的計(jì)數(shù)寄存器的值減為 0 時(shí),就進(jìn)入中斷函數(shù),當(dāng)中斷函數(shù)執(zhí)行完畢之后重新計(jì)時(shí),如此循環(huán),除非它被關(guān)閉。

/*
    brief      delay a time
    param[in]  count: count
    param[out] none
    retval     none
*/
void delay_us(uint32_t count)
{
    delay = count;

    // 使能滴答定時(shí)器  
    SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;

    while(0U != delay){
    }
}

使能了 SysTick 之后,就使用while(0U != delay)語(yǔ)句等待 delay 變量變?yōu)?0,這個(gè)變量是在中斷服務(wù)函數(shù)中被修改的。因此,我們需要編寫相應(yīng)的中斷服務(wù)程序,在本實(shí)驗(yàn)室中我們配置為 10us 中斷一次,每次中斷把 delay 減 1。中斷程序在 gd32f10x_it.c 中實(shí)現(xiàn)。

void SysTick_Handler(void)
{
    delay_decrement ();	
}

SysTick中斷屬于系統(tǒng)異常向量,在gd32f10x_it.c文件中已經(jīng)默認(rèn)有了它的中斷服務(wù)函數(shù)SysTick_Handler(),但內(nèi)容為空。我們找到這個(gè)函數(shù),其調(diào)用了用戶函數(shù)delay_decrement()。后者是由用戶編寫的一個(gè)應(yīng)用程序。

/*
    brief      delay decrement
    param[in]  none
    param[out] none
    retval     none
*/
void delay_decrement(void)
{
    if(0U != delay){
        delay--;
    }
}

每次進(jìn)入 SysTick 中斷就調(diào)用一次 delay_decrement()函數(shù),使全局變量delay 自減一次。用戶函數(shù) delay_us ()在delay 被減至0時(shí),才退出延時(shí)循環(huán),即我們對(duì) delay 賦的值為要中斷的次數(shù)。所以總的延時(shí)時(shí)間 :

T 延時(shí) = T 中斷周期 x delay

至此,SysTick 的精確延時(shí)功能講解完畢。

4 實(shí)驗(yàn)現(xiàn)象

將編譯好的程序下載到板子中,可以看到LED燈不同地閃爍。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1372

    瀏覽量

    40275
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3246

    瀏覽量

    114715
  • Cortex-M
    +關(guān)注

    關(guān)注

    2

    文章

    229

    瀏覽量

    29752
  • Systick
    +關(guān)注

    關(guān)注

    0

    文章

    62

    瀏覽量

    13071
  • GD32
    +關(guān)注

    關(guān)注

    7

    文章

    403

    瀏覽量

    24326
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 1 開(kāi)發(fā)環(huán)境搭建

    開(kāi)發(fā)環(huán)境: MDK:Keil 5.30 開(kāi)發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 GD32F207I-EVAL
    的頭像 發(fā)表于 05-07 23:35 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>1<b class='flag-5'>章</b> <b class='flag-5'>開(kāi)發(fā)</b>環(huán)境搭建

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 4 GD32啟動(dòng)流程詳解(Keil版)

    ,所有的一切都需要由開(kāi)發(fā)者來(lái)設(shè)置,這里處理器是沒(méi)有堆棧,沒(méi)有中斷,更沒(méi)有外圍設(shè)備,這些工作是需要軟件來(lái)指定的,而且不同的CPU類型、不同大小的內(nèi)存和不同種類的外設(shè),其初始化工作都是不同的。本文將以GD32F207IK (基于Cortex-M3)為例進(jìn)行講解。
    的頭像 發(fā)表于 05-10 09:00 ?1.7w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>4<b class='flag-5'>章</b> <b class='flag-5'>GD32</b>啟動(dòng)流程詳解(Keil版)

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 7 定時(shí)器

    系統(tǒng)滴答定時(shí)器一般用來(lái)提供“心跳”作用,而GD32定時(shí)器最基本功能也是定時(shí),可以設(shè)置不同時(shí)間長(zhǎng)度的定時(shí)。定時(shí)器除了最基本的定時(shí)功能外,定時(shí)器與GPIO有掛鉤使得它可以發(fā)揮強(qiáng)大的作用,比如可以輸出
    的頭像 發(fā)表于 05-11 09:00 ?1.2w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>7<b class='flag-5'>章</b> 定時(shí)器

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 8 定時(shí)器

    Modulation” 的縮寫,簡(jiǎn)稱脈寬調(diào)制,是利用微處理器的數(shù)字輸出來(lái)對(duì)模擬電路進(jìn)行控制的一種非常有效的技術(shù)。簡(jiǎn)單一點(diǎn),就是對(duì)脈沖寬度的控制。 GD32 的定時(shí)器除了 TIMER5 和 6(基本定時(shí)器
    的頭像 發(fā)表于 05-12 22:14 ?7926次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>8<b class='flag-5'>章</b> 定時(shí)器

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 11 CPU的高級(jí)代理-DMA

    或者存儲(chǔ)器和存儲(chǔ)器之間的高速數(shù)據(jù)傳輸,因而被廣泛地使用。早在 8086 的應(yīng)用中就已經(jīng)有 Intel 的 8237 這種典型的 DMA 控制器,而 GD32的 DMA 則是以類似外設(shè)的形式添加到 Cortex 內(nèi)核之外的。可以說(shuō),DMA就是CPU的高級(jí)代理,DMA大大減輕了CPU的負(fù)擔(dān)。
    的頭像 發(fā)表于 05-16 08:59 ?3862次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>11<b class='flag-5'>章</b> CPU的高級(jí)代理-DMA

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 12 ADC

    GD32F2系列有 3 個(gè)逐次逼近型的ADC,精度為 12 位,有18個(gè)多路復(fù)用通道,可以轉(zhuǎn)換來(lái)自16個(gè)外部通道和2個(gè)內(nèi)部通道的模擬信號(hào)。其中ADC0 和 ADC1都有 16 個(gè)外部通道, ADC2
    的頭像 發(fā)表于 05-16 09:03 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>12<b class='flag-5'>章</b> ADC

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 14 內(nèi)部溫度傳感器

    GD32 有一個(gè)內(nèi)部的溫度傳感器,可以用來(lái)測(cè)量 CPU 及周圍的溫度(TA)。該溫度傳感器在內(nèi)部和 ADCx_IN16 輸入通道相連接,此通道把傳感器輸出的電壓轉(zhuǎn)換成數(shù)字值。溫度傳感器模擬輸入
    的頭像 發(fā)表于 05-17 08:58 ?5335次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>14<b class='flag-5'>章</b> 內(nèi)部溫度傳感器

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 15 低功耗

    GD32的工作電壓(VDD)為2.0~3.6V。通過(guò)內(nèi)置的電壓調(diào)節(jié)器提供所需的1.8V電源。當(dāng)主電源VDD掉電后,通過(guò)VBAT腳為實(shí)時(shí)時(shí)鐘(RTC)和備份寄存器提供電源。
    的頭像 發(fā)表于 05-17 08:59 ?8048次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>15<b class='flag-5'>章</b> 低功耗

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 16 RTC

    開(kāi)發(fā)環(huán)境: MDK:Keil 5.30 開(kāi)發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 RTC工作原理 1.1 RTC簡(jiǎn)介
    的頭像 發(fā)表于 05-18 22:14 ?7151次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>16<b class='flag-5'>章</b> RTC

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 17 看門狗

    開(kāi)發(fā)環(huán)境: MDK:Keil 5.30 開(kāi)發(fā)板:GD32F207I-EVAL MCU:GD32F207IK GD32 有兩個(gè)看門狗, 一個(gè)是
    的頭像 發(fā)表于 06-03 16:00 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>17<b class='flag-5'>章</b> 看門狗

    【圖書分享】《STM32庫(kù)開(kāi)發(fā)實(shí)戰(zhàn)指南

    GPIO入門之流水燈 4 深入分析流水燈例程 5 調(diào)試程序第二部分 庫(kù)開(kāi)發(fā)中級(jí)
    發(fā)表于 03-13 17:01

    Arduino開(kāi)發(fā)實(shí)戰(zhàn)指南 AVR

    第一基礎(chǔ)1初識(shí)Arduino2編寫Arduino程序
    發(fā)表于 08-03 16:14

    GD32 MCU原理及固件庫(kù)開(kāi)發(fā)指南》 + 初讀感悟

    GD32 MCU原理固件庫(kù)開(kāi)發(fā)指南這本書內(nèi)容豐富,囊括了GD32中的所有外設(shè),書中首先介紹了如何使用MDK或IAR軟件搭建GD32工程環(huán)境,讓初學(xué)者能快速基于工程上手編程。書中主要對(duì)
    發(fā)表于 03-31 22:11

    GD32 MCU原理及固件庫(kù)開(kāi)發(fā)指南》+讀后感

    。 2介紹GD32 MCU快速入門與開(kāi)發(fā)平臺(tái)搭建的方法,包括對(duì)軟硬件開(kāi)發(fā)平臺(tái)、調(diào)試工具、GD32
    發(fā)表于 06-06 21:52

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 19 程序加密

    GD32通過(guò)讀取芯片唯一ID號(hào)來(lái)實(shí)現(xiàn)程序的保護(hù),防止被抄襲。96位的產(chǎn)品唯一身份標(biāo)識(shí)所提供的參考號(hào)碼對(duì)任意一個(gè)GD32微控制器
    的頭像 發(fā)表于 05-20 09:10 ?4139次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>19<b class='flag-5'>章</b> 程序加密
    RM新时代网站-首页