STM32在外部32Mhz晶振下的时钟配置方法

1. 硬件平台

本例程使用的是 STM32F302RDT6 芯片,其时钟配置方法在其它ST单片机中也类似。

2. 实验目的

使用外部 32Mhz 晶振配置系统时钟为 72Mhz

3. 配置原理

根据STM32F302RD芯片的参考手册,可以查看该芯片的时钟树结构,这里我们配置系统时钟 SYSCLK 为72Mhz,所以这里只需要修改 PREDIV 的分频值为4分频,其它 PLL 倍频等配置和使用8Mhz外部晶振时配置相同。
STM32在外部32Mhz晶振下的时钟配置方法_第1张图片

4. 修改配置

(1)打开工程里的 system_stm32f30x.c 文件,找到 SetSysClock() 函数,进行时钟配置修改。这里我们只需要将外部时钟四分频后得到8Mhz的时钟,所示我们只需要添加 RCC->CFGR2 |= (uint32_t)RCC_CFGR2_PREDIV1_DIV4;来实现时钟的分频。

static void SetSysClock(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/

  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------*/
  /* Enable HSE */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }

  if (HSEStatus == (uint32_t)0x01)
  {
    /* Enable Prefetch Buffer and set Flash Latency */
    FLASH->ACR = FLASH_ACR_PRFTBE | (uint32_t)FLASH_ACR_LATENCY_1;

     /* HCLK = SYSCLK / 1 */
     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

     /* PCLK2 = HCLK / 1 */
     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

     /* PCLK1 = HCLK / 2 */
     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

    /* PLL configuration */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9);

    /*!< PREDIV1 input clock divided by 4 */  
    RCC->CFGR2 |= (uint32_t)RCC_CFGR2_PREDIV1_DIV4;     // add. by zhixiaoxing

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock
         configuration. User can add here some code to deal with this error */
  }
}

(2)全局搜索 HSE_VALUE 空定义,在 stm32f30x.h 文件中,这里我们将外部晶振时钟修改为 32000000 Hz

#if !defined  (HSE_VALUE) 
#define HSE_VALUE            ((uint32_t)32000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

5. 查看总线时钟

在对STM32时钟进行配置后,为了进一步验证配置的正确性,我们可以使用仿真来查看系统各总线的时钟频率。首先在主函数中添加如下代码:

int main(void)
{
    RCC_ClocksTypeDef get_rcc_clock;    
    RCC_GetClocksFreq(&get_rcc_clock); // 获取系统时钟配置
}

通过仿真可以查看各总线时钟的配置频率,如下图所示:
STM32在外部32Mhz晶振下的时钟配置方法_第2张图片
Note:注意一定要修改宏 #define HSE_VALUE ((uint32_t)32000000) /!< Value of the External oscillator in Hz /的值,因为时钟使用该宏定义进行计算。

5. 慎入此坑

在时钟配置时,需要注意的一些问题:
(1)在时钟树任何一个倍频的环节都不能超频,即使后面分频系数较大,还是会导致时钟配置失败;
(2)在配置外部晶振四分频时,发现了一个诡异的问题,CFGR2寄存器一定要在CFGR寄存器之后,否则会导致CGFR2寄存器的值与配置的不符,至今不明其诡异之处?

/* PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9);

/*!< PREDIV1 input clock divided by 4 */  
RCC->CFGR2 |= (uint32_t)RCC_CFGR2_PREDIV1_DIV4;     // add. by zhixiaoxing

你可能感兴趣的:(单片机学习笔记)