STM32系统时钟

 

STM32中,有五个时钟源,为HSIHSELSILSEPLL

HSI是高速内部时钟,RC振荡器,频率为8MHz

HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz

LSI是低速内部时钟,RC振荡器,频率为40kHz

LSE是低速外部时钟,接频率为32.768kHz的石英晶体。

PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz

 

STM32上如果不使用外部晶振,OSC_INOSC_OUT的接法

如果使用内部RC振荡器而不使用外部晶振,请按照下面方法处理:


1
)对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT应悬空。
2
)对于少于100脚的产品,有2种接法:
   2.1
OSC_INOSC_OUT分别通过10K电阻接地。此方法可提高EMC性能。
   2.2
)分别重映射OSC_INOSC_OUTPD0PD1,再配置PD0PD1为推挽输出并输出'0'。此方法可以减小功耗并(相对上面2.1)节省2个外部电阻。

 

使用HSE时钟,程序设置时钟参数流程
1
、将RCC寄存器重新设置为默认值   RCC_DeInit;
2
、打开外部高速时钟晶振HSE    RCC_HSEConfig(RCC_HSE_ON);
3
、等待外部高速时钟晶振工作    HSEStartUpStatus = RCC_WaitForHSEStartUp();
4
、设置AHB时钟         RCC_HCLKConfig;
5
、设置高速AHB时钟     RCC_PCLK2Config;
6
、设置低速速AHB时钟   RCC_PCLK1Config;
7
、设置PLL              RCC_PLLConfig;

8
、打开PLL              RCC_PLLCmd(ENABLE);
9
、等待PLL工作   while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
10
、设置系统时钟        RCC_SYSCLKConfig;
11
、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
12
、打开要使用的外设时钟    RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

下面来看一下STM32默认的时钟配置如下: 

STM32对时钟的默认配置是在:system_stm32f10x.c    函数中完成的。

在该函数的最开头(第74--91行)有如下代码:

    
#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                            //系统默认将时钟初始化为72MHz
#endif

/*!< Uncomment the following line if you need to use external SRAM mounted
     on STM3210E-EVAL board (STM32 High density and XL-density devices) or on 
     STM32100E-EVAL board (STM32 High-density value line devices) as data memory */ 
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
/* #define DATA_IN_ExtSRAM */
#endif

/*!< Uncomment the following line if you need to relocate your vector Table in
     Internal SRAM. */ 
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET  0x0 /*!< Vector Table base offset field. 
                                  This value must be a multiple of 0x100. */

上述代码主要功能是:系统默认将时钟初始化为72MHz

 

 

在system_stm32f10x.c的最后(第918--1020行)有如下代码:

 

static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* 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;     //等待外部时钟就绪或者超时(等待500个时钟周期)退出
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)  //判断外部时钟是否就绪,就绪之后设置HSEStatus为1
  {
    HSEStatus = (uint32_t)0x01;
  }
  else            //若外部高速时钟没有就绪,设置HSEStatus为0
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)     //如果外部告诉时钟设置就绪
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;     //使能预取址缓冲区

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    


    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;    //设置PCLK1时钟由倍频器而分频后输入(即设置时钟为时钟线1的频率为32M)

#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* 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)0x08)    //锁相环时钟准备就绪
    {
    }
  }
  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 */
  }
}
#endif

/**
  * @}
  */

/**
  * @}
  */
  
/**
  * @}
  */    
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

 

上述代码对关键语句都有注释,它完成的功能是将系统的时钟总线1配置为外部高速时钟2分频之后由倍频器倍频9倍之后有锁相环输出(若使用外部8M晶振,时钟被配置为36MHz),将系统时钟总线2配置为外部高速时钟倍频9倍之后有锁相环输出(若使用外部8M晶振,时钟被配置为72MHz)。

系统时钟2上挂的外部设备有: 

             RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
  *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
  *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
  *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
  *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
  *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
  *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11 

(摘自固件库3.4)

 

系统时钟1上挂的外设有:

RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4,
  *          RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7,
  *          RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3,
  *          RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, 
  *          RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2,
  *          RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP,
  *          RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC,
  *          RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14

(摘自固件库3.4)

 

 

虽然库函数默认配置了72MHZ的频率,但是为了提高使用的灵活性,建议在编程时自行配置系统时钟,具体配置方法可以参看一下代码;

/*******************************************************************************

* Function Name  : RCC_Configuration 

* Description    :  RCC配置(使用外部8MHz晶振)

* Input            

* Output         

* Return         

*******************************************************************************/

void RCC_Configuration(void)

{

  /*将外设RCC寄存器重设为缺省值*/

  RCC_DeInit();

 

  /*设置外部高速晶振(HSE*/

  RCC_HSEConfig(RCC_HSE_ON);   //RCC_HSE_ON——HSE晶振打开(ON)

 

  /*等待HSE起振*/

  HSEStartUpStatus = RCC_WaitForHSEStartUp();

 

  if(HSEStartUpStatus == SUCCESS)        //SUCCESSHSE晶振稳定且就绪

  {

    /*设置AHB时钟(HCLK*/ 

    RCC_HCLKConfig(RCC_SYSCLK_Div1);  //RCC_SYSCLK_Div1——AHB时钟系统时钟

 

    /* 设置高速AHB时钟(PCLK2*/ 

    RCC_PCLK2Config(RCC_HCLK_Div1);   //RCC_HCLK_Div1——APB2时钟= HCLK

 

    /*设置低速AHB时钟(PCLK1*/    

RCC_PCLK1Config(RCC_HCLK_Div2);   //RCC_HCLK_Div2——APB1时钟= HCLK / 2

 

    /*设置FLASH存储器延时时钟周期数*/

    FLASH_SetLatency(FLASH_Latency_2);    //FLASH_Latency_2  2延时周期

   

 /*选择FLASH预取指缓存的模式*/  

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);       // 预取指缓存使能

 

    /*设置PLL时钟源及倍频系数*/ 

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);     

// PLL的输入时钟= HSE时钟频率RCC_PLLMul_9——PLL输入时钟x 9

   

  /*使能PLL */

    RCC_PLLCmd(ENABLE); 

 

    /*检查指定的RCC标志位(PLL准备好标志)设置与否*/   

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)      

       {

       }

 

    /*设置系统时钟(SYSCLK*/ 

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 

//RCC_SYSCLKSource_PLLCLK——选择PLL作为系统时钟

 

    /* PLL返回用作系统时钟的时钟源*/

    while(RCC_GetSYSCLKSource() != 0x08)        //0x08PLL作为系统时钟

       

       }

     }

你可能感兴趣的:(嵌入式,stm32)