STM32时钟配置与SysTick配置_基于STM32F103

【一】前言

  • STM32前后台程序编程时,最基本的配置应当是对其时钟和系统定时器的配置,对标准库而言,调用SysTick_Init ();。如果采用HAL库,首先还应该调用HAL_Init();初始化HAL库。
  • 此处采用标准库。

【二】STM32时钟配置

1、概述

  • RCC(Reset Clock Controller)中时钟控制器,主要关注时钟树。
  • 一般配置:PCLK2(APB2外设)=HCLK(SDIO外设时钟只能)=SYSCLK(系统时钟)=PLLCLK=72MHz,PCLK1=HCLK/2=36MHz。
  • 各类时钟解释:
    注1:HSE(High speed external clock):高速外部时钟。由外部晶振通过OSC_IN和OSC_OUT提供。如果是无源晶振,接两根引脚;如果是有源晶振,接OSC_IN,另一根悬空。一般采用8MHz的无源晶振。
    注2:LSE(Low speed external clock):低速外部时钟。由外部晶振通过OSC32_IN和OSC32_OUT提供,一般为32.768KHz,提供RTC的时钟。
    注3:HSI(High speed internal clock):高速内部时钟,8MHz,可备用,当HSE故障时,开启CSS和CSS中断的情况下,HSI可提供系统运行时钟,但最高只能是64MHz。
    注4:LSI(Low speed internal clock):低速内部时钟,40KHz,提供给独立看门狗。
    注5:PLL(phaselocked loop):锁相环倍频输出。由HSE或HSI/2提供,可设置2~16倍输出,一般选用HSE路径,9倍频(72MHz)。
    1.PCLK2(Peripheral Clock 2):APB2(Advanced Peripheral Bus,高级外围总线)的时钟,提供给外设的时钟,如GPIO/USART1/SPI1等。一般设置为一分频,72MHz。
    2.HCLK(High Performance Clock):AHB(Advanced High Performance Bus,高级高性能总线)的时钟,提供给AHB总线、核心存储器、DMA等的时钟,可通过AHB预分频器分频得到。
    3.PCLK(Peripheral Clock):外设总线时钟,属于低速率的,提供给USART2/3/4/5、SPI2/3、IIC1/2等。
    关于系统时钟配置的函数存在于库函数system_stm32f10x.c中。
    这里写图片描述

2、时钟配置

  • 对标准库来说,如果定义了时钟频率,则系统会默认初始化该时钟频率。

在system_stm32f10x.c中:

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif
#ifdef SYSCLK_FREQ_HSE
  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
  uint32_t SystemCoreClock         = HSI_VALUE;        /*!< System Clock Frequency (Core Clock) */
#endif
#ifdef SYSCLK_FREQ_HSE
  static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
  static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
  static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
  static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
  static void SetSysClockTo56(void);  
#elif defined SYSCLK_FREQ_72MHz
  static void SetSysClockTo72(void);
#endif

这三段代码可以看出,定义了SYSCLK_FREQ_72MHz,则会调用SetSysClockTo72(void);函数。以下看该函数的功能描述:

/**
  * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
  *         and PCLK1 prescalers. 
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
  ……

综上,可以通过定义时钟频率来设置系统的时钟,都是标准库已经写好的函数。

3、时钟输出

配置PA8复用为MCO引脚输出:

void MCO_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
}

【三】STM32 SysTick系统定时器配置

  • SysTick是CM3的内核外设,是一个24位的向下递减计数器,每次计数时间是1/SYSCLK,即1/72000000。
  • SysTick计数时间的计算:t=重装载值*1/AHB时钟频率。1/AHB时钟频率即是计数一次的时间。一般把重装载值定为72000000/100000=720,则10us中断一次;一般不设置为1us中断一次,这样中断频率太高,偏移了程序重心。
  • 定时器配置步骤:
    1.初始化:
/**
  * @brief  启动系统滴答定时器SysTick
  * @param  none
  * @retval none
  */
void SysTick_Init( void )
{
    /* SystemFrequency / 1000    1ms
     * SystemFrequency / 100000  10us
     * SystemFrequency / 1000000 1us
     */
    if ( SysTick_Config(SystemCoreClock / 100000) ) 
    { 
        /* Capture error */ 
        while (1);
    }
    //关闭滴答定时器
    SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}

2.定时函数:

/**
  * @brief   10us延时程序
  * @param  
  * @arg nTime: Delay_10us( 1 ) 为10us
  * @retval  none
  */
void Delay_10us( __IO u32 nTime )
{ 
    TimingDelay = nTime;    

    //使能滴答定时器
    SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;

    while( TimingDelay != 0 );
}

3.中断服务函数:

static __IO u32 TimingDelay = 0;
/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
    TimingDelay_Decrement();    
}
/**
 * @brief  获取节拍程序,10us减1
 * @param  none
 * @retval none
 * @attention 在SysTick_Handler()中调用
  */
void TimingDelay_Decrement(void)
{
    if ( TimingDelay != 0x00 )
    { 
        TimingDelay --;

    }
    if(TimeLapseflag != 0x00)
    {
        TimeLapseflag --;
    }
}
  • 另一种微秒级定时编程:
void SysTick_Delay_Us( __IO uint32_t us)
{
    uint32_t i;
    SysTick_Config(SystemCoreClock/1000000);

    for(i=0;i<us;i++)
    {
        //当计数器的值减到0时,CTRL寄存器的位16会置1
        while(!((SysTick->CTRL)&(1<<16)));
    }
    SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}

同理可以写出ms级的定时程序。


猜你喜欢

转载自blog.csdn.net/u010834669/article/details/80204195