GD32F103學(xué)習(xí)筆記(6)——系統(tǒng)延時(shí)使用

一、簡(jiǎn)介

SysTick —系統(tǒng)定時(shí)器是屬于 CM3 內(nèi)核中的一個(gè)外設(shè),內(nèi)嵌在 NVIC 中。系統(tǒng)定時(shí)器是一個(gè) 24bit 的向下遞減的計(jì)數(shù)器,計(jì)數(shù)器每計(jì)數(shù)一次的時(shí)間為 1/SYSCLK,一般我們?cè)O(shè)置系統(tǒng)時(shí)鐘 SYSCLK 等于 108M。當(dāng)重裝載數(shù)值寄存器的值遞減到 0 的時(shí)候,系統(tǒng)定時(shí)器就產(chǎn)生一次中斷,以此循環(huán)往復(fù)。

因?yàn)?SysTick 是屬于 CM3 內(nèi)核的外設(shè),所以所有基于 CM3 內(nèi)核的單片機(jī)都具有這個(gè)系統(tǒng)定時(shí)器,使得軟件在 CM3 單片機(jī)中可以很容易的移植。系統(tǒng)定時(shí)器一般用于操作系統(tǒng),用于產(chǎn)生時(shí)基,維持操作系統(tǒng)的心跳。

二、API說明

2.1 外設(shè)寄存器說明

SysTick寄存器列表如下表所示:

寄存器名稱 寄存器描述
CTRL 系統(tǒng)控制和狀態(tài)寄存器
LOAD 系統(tǒng)重載值寄存器
VAL 系統(tǒng)當(dāng)前值寄存器
CALIB 系統(tǒng)校準(zhǔn)寄存器

參考 core_cm3.h 文件中定義的結(jié)構(gòu)體類型 SysTick_Type

2.2 外設(shè)庫函數(shù)說明

以下 SYSTICK 接口位于 GD32F10x_Firmware_Library_V2.2.2\Firmware\GD32F10x_standard_peripheral\Include\gd32f10x_misc.h。

2.2.1 systick_clksource_set

功能 設(shè)置SysTick時(shí)鐘源
函數(shù)定義 void systick_clksource_set(uint32_t systick_clksource)
參數(shù) systick_clksource:SysTick時(shí)鐘源
返回

systick_clksource: SysTick時(shí)鐘源,詳細(xì)列表如下:

含義
SYSTICK_CLKSOURCE_HCLK SysTick時(shí)鐘源為AHB時(shí)鐘
SYSTICK_CLKSOURCE_HCLK_DIV8 SysTick時(shí)鐘源為AHB時(shí)鐘的8分頻

三、中斷方式

3.1 systick.c

/*!
    \file    systick.c
    \brief   the systick configuration file

    \version 2014-12-26, V1.0.0, firmware for GD32F10x
    \version 2017-06-20, V2.0.0, firmware for GD32F10x
    \version 2018-07-31, V2.1.0, firmware for GD32F10x
    \version 2020-09-30, V2.2.0, firmware for GD32F10x
*/

/*
    Copyright (c) 2020, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

#include "gd32f10x.h"
#include "systick.h"

volatile static uint32_t delay;

/*!
    \brief      configure systick
    \param[in]  none
    \param[out] none
    \retval     none
*/
void systick_config(void)
{
    /* setup systick timer for 1000Hz interrupts */
    if (SysTick_Config(SystemCoreClock / 1000U)){
        /* capture error */
        while (1){
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

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

    while(0U != delay){
    }
}

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

SysTick 初始化函數(shù)由用戶編寫,里面調(diào)用了 SysTick_Config() 這個(gè)固件庫函數(shù),通過設(shè)置該固件庫函數(shù)的形參,就決定了系統(tǒng)定時(shí)器經(jīng)過多少時(shí)間就產(chǎn)生一次中斷。

  • SysTick 中斷時(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} =108MHz 。 如果設(shè)置 VALUE_{LOAD} 為 108,那中斷一次的時(shí)間 T_{INT}=108/108M=1us。不過 1us 的中斷沒啥意義,整個(gè)程序的重心都花在進(jìn)出中斷上了,根本沒有時(shí)間處理其他的任務(wù)。
SysTick_Config(SystemCoreClock / 1000))

SysTick_Config() 的形我們配置為 SystemCoreClock / 1000=108M/1000=108,000,從剛剛分析我們知道這個(gè)形參的值最終是寫到重裝載寄存器 LOAD 中的,從而可知我們現(xiàn)在把 SysTick 定時(shí)器中斷一次的時(shí)間 T_{INT}=108,000/108M=1ms。

  • SysTick 定時(shí)時(shí)間的計(jì)算
    當(dāng)設(shè)置好中斷時(shí)間 T_{INT} 后,我們可以設(shè)置一個(gè)變量 t,用來記錄進(jìn)入中斷的次數(shù),那么變量 t 乘以中斷的時(shí)間 T_{INT} 就可以計(jì)算出需要定時(shí)的時(shí)間。

  • SysTick 定時(shí)函數(shù)
    現(xiàn)在我們定義一個(gè)毫秒級(jí)別的延時(shí)函數(shù),形參為 count,當(dāng)用這個(gè)形參乘以中斷時(shí)間 T_{INT} 就得出我們需要的延時(shí)時(shí)間。

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

    while(0U != delay){
    }
}

函數(shù) delay_1ms() 中我們等待 delay 為 0,當(dāng) delay 為 0 的時(shí)候表示延時(shí)時(shí)間到。變量 delay 在中斷函數(shù)中遞減,即 SysTick 每進(jìn)一次中斷即 1ms 的時(shí)間 delay 遞減一次。

3.2 systick.h

/*!
    \file    systick.h
    \brief   the header file of systick

    \version 2014-12-26, V1.0.0, firmware for GD32F10x
    \version 2017-06-20, V2.0.0, firmware for GD32F10x
    \version 2018-07-31, V2.1.0, firmware for GD32F10x
    \version 2020-09-30, V2.2.0, firmware for GD32F10x
*/

/*
    Copyright (c) 2020, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

#ifndef SYSTICK_H
#define SYSTICK_H

#include <stdint.h>

/* configure systick */
void systick_config(void);
/* delay a time in milliseconds */
void delay_1ms(uint32_t count);
/* delay decrement */
void delay_decrement(void);

#endif /* SYSTICK_H */

3.3 gd32f10x_it.c

/*!
    \file    gd32f10x_it.c
    \brief   interrupt service routines

    \version 2014-12-26, V1.0.0, firmware for GD32F10x
    \version 2017-06-20, V2.0.0, firmware for GD32F10x
    \version 2018-07-31, V2.1.0, firmware for GD32F10x
    \version 2020-09-30, V2.2.0, firmware for GD32F10x
*/

/*
    Copyright (c) 2020, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/
#include "gd32f10x_it.h"
#include "systick.h"

/*!
    \brief      this function handles NMI exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void NMI_Handler(void)
{
}

/*!
    \brief      this function handles HardFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void HardFault_Handler(void)
{
    /* if Hard Fault exception occurs, go to infinite loop */
    while(1){
    }
}

/*!
    \brief      this function handles MemManage exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void MemManage_Handler(void)
{
    /* if Memory Manage exception occurs, go to infinite loop */
    while(1){
    }
}

/*!
    \brief      this function handles BusFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void BusFault_Handler(void)
{
    /* if Bus Fault exception occurs, go to infinite loop */
    while(1){
    }
}

/*!
    \brief      this function handles UsageFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void UsageFault_Handler(void)
{
    /* if Usage Fault exception occurs, go to infinite loop */
    while(1){
    }
}

/*!
    \brief      this function handles SVC exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SVC_Handler(void)
{
}

/*!
    \brief      this function handles DebugMon exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void DebugMon_Handler(void)
{
}

/*!
    \brief      this function handles PendSV exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void PendSV_Handler(void)
{
}

/*!
    \brief      this function handles SysTick exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SysTick_Handler(void)
{
    delay_decrement();
}
  • SysTick 中斷服務(wù)函數(shù)
void SysTick_Handler(void)
{
    delay_decrement();
}

中斷復(fù)位函數(shù)調(diào)用了另外一個(gè)函數(shù) delay_decrement(),原型如下:

void delay_decrement(void)
{
    if (0U != delay){
        delay--;
    }
}

delay 的值等于延時(shí)函數(shù)中傳進(jìn)去的 count 的值,比如 count=1000,則延時(shí)的時(shí)間等于 1000*1ms=1s。

3.4 main.c

#include "gd32f10x.h"
#include "systick.h"

int main(void)
{
    systick_config();//系統(tǒng)主頻108MHZ,采用外部晶振,由兩個(gè)宏決定(__SYSTEM_CLOCK_108M_PLL_HXTAL與HXTAL_VALUE)
    
    LED_GPIO_Init();// LED燈模塊初始化
    
    while(1)
    {
          LED_ON;
          delay_1ms(500);
          LED_OFF;
          delay_1ms(500);
    }
}

四、輪詢方式

直接方便,套路淺

4.1 systick.c

/*!
    \file    systick.c
    \brief   the systick configuration in polling mode

    \version 2020-09-30, V1.0.0, firmware for GD32F10x
*/

/*
    Copyright (c) 2020, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

#include "gd32f10x.h"
#include "systick.h"

volatile static float count_1us = 0;
volatile static float count_1ms = 0;

/*!
    \brief      configure systick
    \param[in]  none
    \param[out] none
    \retval     none
*/
void systick_config(void)
{
    /* systick clock source is from HCLK/8 內(nèi)部時(shí)鐘的108M/8分頻 */
    systick_clksource_set(SYSTICK_CLKSOURCE_HCLK_DIV8);
    count_1us = (float)SystemCoreClock/8000000;//延時(shí)1us需要的時(shí)鐘數(shù)量 108M/8M = 13.5 
    count_1ms = (float)count_1us * 1000;//延時(shí)1ms需要的時(shí)鐘數(shù)量 108M/8M *1000= 13500 
}

/*!
    \brief      delay a time in microseconds in polling mode
    \param[in]  count: count in microseconds
    \param[out] none
    \retval     none
*/
void delay_1us(uint32_t count)
{
    uint32_t ctl;
    
    /* reload the count value */
    SysTick->LOAD = (uint32_t)(count * count_1us);
    /* clear the current count value */
    SysTick->VAL = 0x0000U;
    /* enable the systick timer */
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
    /* wait for the COUNTFLAG flag set */
    do{
        ctl = SysTick->CTRL;
    }while((ctl&SysTick_CTRL_ENABLE_Msk)&&!(ctl & SysTick_CTRL_COUNTFLAG_Msk));
    /* disable the systick timer */
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
    /* clear the current count value */
    SysTick->VAL = 0x0000U;
}

/*!
    \brief      delay a time in milliseconds in polling mode
    \param[in]  count: count in milliseconds
    \param[out] none
    \retval     none
*/
void delay_1ms(uint32_t count)
{
    uint32_t ctl;
    
    /* reload the count value */
    SysTick->LOAD = (uint32_t)(count * count_1ms);
    /* clear the current count value */
    SysTick->VAL = 0x0000U;
    /* enable the systick timer */
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
    /* wait for the COUNTFLAG flag set */
    do{
        ctl = SysTick->CTRL;
    }while((ctl&SysTick_CTRL_ENABLE_Msk)&&!(ctl & SysTick_CTRL_COUNTFLAG_Msk));
    /* disable the systick timer */
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
    /* clear the current count value */
    SysTick->VAL = 0x0000U;
}

GD32F103通過AHB時(shí)鐘(HCLK)即108MHz的8分頻后作為Cortex系統(tǒng)定時(shí)器(SysTick)的外部時(shí)鐘。

4.2 systick.h

/*!
    \file    systick.h
    \brief   the header file of systick

    \version 2020-09-30, V1.0.0, firmware for GD32F10x
*/

/*
    Copyright (c) 2020, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

#ifndef SYSTICK_H
#define SYSTICK_H

#include <stdint.h>

/* configure systick */
void systick_config(void);
/* delay a time in milliseconds */
void delay_1ms(uint32_t count);
/* delay a time in microseconds */
void delay_1us(uint32_t count);

#endif /* SYSTICK_H */

4.3 main.c

#include "gd32f10x.h"
#include "systick.h"

int main(void)
{
    systick_config();//系統(tǒng)主頻108MHZ,采用外部晶振,由兩個(gè)宏決定(__SYSTEM_CLOCK_108M_PLL_HXTAL與HXTAL_VALUE)
    
    LED_GPIO_Init();// LED燈模塊初始化
    
    while(1)
    {
          LED_ON;
          delay_1ms(500);
          LED_OFF;
          delay_1us(500000);
    }
}

? 由 Leung 寫于 2022 年 4 月 13 日

? 參考:14. GD32F103C8T6入門教程-Systick定時(shí)器
    GD32精確延時(shí)和時(shí)間戳

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容