STM32开发 -- 时钟系统详解

发布者:cwm6269310最新更新时间:2019-09-02 来源: eefocus关键字:STM32  时钟系统  RTC 手机看文章 扫描二维码
随时随地手机看文章

上一篇文章讲了RTC,里面其实已经包含了时钟系统的介绍了。这篇文章将再详细的讲一下。


一、时钟系统框图


这里写图片描述

二、时钟系统

STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。

①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。

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

③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 

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

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

系统时钟SYSCLK可来源于三个时钟源:

①、HSI振荡器时钟

②、HSE振荡器时钟

③、PLL时钟

STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。

任何一个外设在使用之前,必须首先使能其相应的时钟。

三、RCC相关配置寄存器

        /** 

          * @brief Reset and Clock Control

          */

        typedef struct

        {

          __IO uint32_t CR;           // HSI,HSE,CSS,PLL等的使能和就绪标志位 

          __IO uint32_t CFGR;         // PLL等的时钟源选择,分频系数设定

          __IO uint32_t CIR;          // 清除/使能 时钟就绪中断

          __IO uint32_t APB2RSTR;     // APB2线上外设复位寄存器

          __IO uint32_t APB1RSTR;     // APB1线上外设复位寄存器

          __IO uint32_t AHBENR;       // DMA,SDIO等时钟使能

          __IO uint32_t APB2ENR;      // APB2线上外设时钟使能

          __IO uint32_t APB1ENR;      // APB1线上外设时钟使能

          __IO uint32_t BDCR;         // 备份域控制寄存器

          __IO uint32_t CSR;          // 控制状态寄存器


        #ifdef STM32F10X_CL  

          __IO uint32_t AHBRSTR;

          __IO uint32_t CFGR2;

        #endif /* STM32F10X_CL */ 


        #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)   

          uint32_t RESERVED0;

          __IO uint32_t CFGR2;

        #endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */ 

        } RCC_TypeDef;


四、RCC相关头文件和固件库源文件

所在文件:stm32f10x_rcc.c


时钟使能配置:

     RCC_LSEConfig() 、RCC_HSEConfig()、

     RCC_HSICmd() 、 RCC_LSICmd() 、 RCC_PLLCmd() ……


时钟源相关配置:

     RCC_PLLConfig ()、 RCC_SYSCLKConfig() 、

     RCC_RTCCLKConfig() …


分频系数选择配置:

      RCC_HCLKConfig() 、 RCC_PCLK1Config() 、 RCC_PCLK2Config()…


外设时钟使能:

     RCC_APB1PeriphClockCmd():  //APB1线上外设时钟使能

     RCC_APB2PeriphClockCmd();  //APB2线上外设时钟使能

     RCC_AHBPeriphClockCmd();   //AHB线上外设时钟使能


其他外设时钟配置:

    RCC_ADCCLKConfig ();  RCC_RTCCLKConfig();


状态参数获取参数:

     RCC_GetClocksFreq();

     RCC_GetSYSCLKSource();

     RCC_GetFlagStatus()


RCC中断相关函数 :

    RCC_ITConfig() 、 RCC_GetITStatus() 、 RCC_ClearITPendingBit()…


五、系统时钟初始化函数

系统时钟初始化函数:SystemInit();

我们在 STM32开发 – 启动流程 中讲过:


使用V3.5版本的库函数,该函数在系统启动之后会自动调用:

; Reset handler

Reset_Handler    PROC

                 EXPORT  Reset_Handler             [WEAK]

        IMPORT  SystemInit

        IMPORT  __main

                 LDR     R0, =SystemInit

                 BLX     R0

                 LDR     R0, =__main

                 BX      R0

                 ENDP


系统复位后先执行SystemInit,再执行main函数

 通过修改SystemInit函数名称,可以自定义系统初始化过程


在system_stm32f10x.c文件中找到SystemInit(void)源码:

/**

  * @brief  Setup the microcontroller system

  *         Initialize the Embedded Flash Interface, the PLL and update the

  *         SystemCoreClock variable.

  * @note   This function should be used only after reset.

  * @param  None

  * @retval None

  */

void SystemInit (void)

{

  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */

  /* Set HSION bit */

  RCC->CR |= (uint32_t)0x00000001;    //RCC_CR寄存器最低位置1:打开HSI(内部高速时钟8M)


  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */

#ifndef STM32F10X_CL

  RCC->CFGR &= (uint32_t)0xF8FF0000;

#else                      //stm32f103ZET6为大容量芯片HD

  RCC->CFGR &= (uint32_t)0xF0FF0000;     //RCC_CFGR寄存器初始化

#endif /* STM32F10X_CL */


  /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR &= (uint32_t)0xFEF6FFFF;    //将RCC_CR寄存器HSEON,CSSON,PLLON位置0


  /* Reset HSEBYP bit */

  RCC->CR &= (uint32_t)0xFFFBFFFF;    //将RCC_CR寄存器HSEBYP位置0


  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */

  RCC->CFGR &= (uint32_t)0xFF80FFFF;   //将RCC_CFGR寄存器PLLSRC, PLLXTPRE,                         //PLLMUL,USBPRE/OTGFSPRE位置0


#ifdef STM32F10X_CL

  /* Reset PLL2ON and PLL3ON bits */

  RCC->CR &= (uint32_t)0xEBFFFFFF;


  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x00FF0000;


  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;


  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

#else                      //stm32f103ZET6为大容量芯片HD

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;        //关闭所有的中断和对应的位(初始化中断)

#endif /* STM32F10X_CL */


#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)

  #ifdef DATA_IN_ExtSRAM

    SystemInit_ExtMemCtl();

  #endif /* DATA_IN_ExtSRAM */

#endif


  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */

  /* Configure the Flash Latency cycles and enable prefetch buffer */

  SetSysClock();


#ifdef VECT_TAB_SRAM

  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */

#else

  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */

#endif

}


源码解析

参看:系统初始化函数SystemInit讲解

参看:第一个函数SystemInit()里面有些啥


RCC->CR |= (uint32_t)0x00000001;


操作时钟控制寄存器,将内部8M高速时钟使能,从这里可以看出系统启动后是首先依靠内部时钟源而工作的。


#ifndef STM32F10X_CL

  RCC->CFGR &= (uint32_t)0xF8FF0000;

#else

  RCC->CFGR &= (uint32_t)0xF0FF0000;


这两行代码则是操作时钟配置寄存器,其主要设置了MCO(微控制器时钟输出)PLL相关(PLL倍频系数,PLL输入时钟源),ADCPRE(ADC时钟),PPRE2(高速APB分频系数),PPRE1(低速APB分频系数),HPRE(AHB预分频系数),SW(系统时钟切换),开始时,系统时钟切换到HSI,由它作为系统初始化时钟。宏STM32F10X_CL是跟具体STM32芯片相关的一个宏。


 /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR &= (uint32_t)0xFEF6FFFF;

 

  /* Reset HSEBYP bit */

  RCC->CR &= (uint32_t)0xFFFBFFFF;

 

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */

  RCC->CFGR &= (uint32_t)0xFF80FFFF;


这几句话则是在先关闭HSE、CSS、PLL等的情况下配置好与之相关参数然后开启,达到生效的目的。



#ifdef STM32F10X_CL

  /* Reset PLL2ON and PLL3ON bits */

  RCC->CR &= (uint32_t)0xEBFFFFFF;

 

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x00FF0000;

 

  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;

 

  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;      

#else

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;

#endif /* STM32F10X_CL */


这段主要是跟中断设置有关。开始时,我们需要禁止所有中断并且清除所有中断标志位。不同硬件有不同之处。



#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)

  #ifdef DATA_IN_ExtSRAM

    SystemInit_ExtMemCtl(); 

  #endif /* DATA_IN_ExtSRAM */

#endif


这段跟设置外部RAM有关。


SetSysClock();


此函数主要是配置系统时钟频率。HCLK,PCLK2,PCLK1的分频值,分别代表AHB,APB2,和APB1。当然还干了其它的事情,配置FLASH延时周期和使能预取缓冲区。


/**

  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.

  * @param  None

  * @retval None

  */

static void SetSysClock(void)

{

#ifdef SYSCLK_FREQ_HSE

  SetSysClockToHSE();

#elif defined SYSCLK_FREQ_24MHz

  SetSysClockTo24();

#elif defined SYSCLK_FREQ_36MHz

  SetSysClockTo36();

#elif defined SYSCLK_FREQ_48MHz

  SetSysClockTo48();

#elif defined SYSCLK_FREQ_56MHz

  SetSysClockTo56();  

#elif defined SYSCLK_FREQ_72MHz

  SetSysClockTo72();

#endif

 

 /* If none of the define above is enabled, the HSI is used as System clock

    source (default after reset) */ 

}


查看可得默认定义系统时钟为72MHz


#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


通过SystemCoreClock获取当前系统时钟频率


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

*  Clock Definitions

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

#ifdef SYSCLK_FREQ_HSE

  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< System Clock Frequency (Core Clock) */

[1] [2]
关键字:STM32  时钟系统  RTC 引用地址:STM32开发 -- 时钟系统详解

上一篇:STM32开发 -- Git的详细使用
下一篇:STM32开发 -- 开发环境搭建

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved