欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-13 17:31:54
...

【一】前言

  • 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中。
    STM32时钟配置与SysTick配置_基于STM32F103

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级的定时程序。