STM32F10xx时钟系统

一、如下图所示为STM32F10XX时钟系统框图

在这里插入图片描述

  • 上图所示5个蓝色框框为STM32F10xx系列芯片的时钟源,即时钟的来源(STM32F1系列芯片的系统时钟、所有外设时钟等全部来源于这5个时钟源)
  • 上图所示SYSCLK系统时钟是最重要的一个时钟,其他的外设时钟全部来自于SYSCLK系统时钟。
  • PLL锁相环是用来倍频的。
  • 上图所示CSS为时钟监控系统,用来检测一旦HSE外部高速时钟失效,则切换到内部高速时钟作为系统时钟,防止外部晶振不起振导致系统崩溃。
  • MCO是STM32F1XX芯片输出内部时钟的一个引脚,对应芯片的PA8引脚。

在这里插入图片描述
在这里插入图片描述

二、下图所示为RCC相关配置寄存器,红色的为常用的时钟寄存器

在这里插入图片描述

  • CR寄存器是用来配置时钟源的使能情况的。对于文章开头的时钟系统结构图里蓝色框框里的时钟源,在使用之前都需要使能才能正常工作。使能的瞬间这个时钟还没有稳定,系统需要等待这个时钟源稳定,所以需要判断标志位来判断该时钟源是否输入稳定了。
    在这里插入图片描述

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

在这里插入图片描述

四、SystemInit时钟系统初始化函数剖析

/**
  * @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)
{
  /* 将RCC时钟配置重置为默认的重置状态(用于调试) */
  /* 设置 CR 寄存器的 HSION 位为1 */
  RCC->CR |= (uint32_t)0x00000001;

  /* 复位SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO 位 */
#ifndef STM32F10X_CL  //因为我们用的是STM32大容量芯片,定义的宏是STM32F10X_HD,所以这个#ifdef不成立.
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else //大容量芯片执行这里,配置CFGR寄存器。复位SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO 位为初始化状态。
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* 复位 CR 寄存器的 HSEON, CSSON and PLLON 位*/
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* 复位 CR HSEBYP 位 */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* 复位 PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE 位 */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL //因为我们定义的(STM32F10X_HD),所以下面的部分代码不会执行
  /* 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 */
    
//因为我们宏定义了STM32F10X_HD,所以下面的代码会执行,进入SystemInit_ExtMemCtl()函数
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* 配置系统时钟频率, HCLK, PCLK2 and PCLK1 分频器*/
  /* 配置Flash延迟周期并启用预取缓冲区 */
  SetSysClock();

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* 在内部SRAM中的向量表重定位. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* 内部FLASH中的向量表重定位. */
#endif 
}
/**
  * @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
 
 /* 如果以上定义都没有启用,则HSI将用作系统时钟源(重置后默认) */ 
}

在这里插入图片描述

/*
	配置系统时钟为72MHz
*/
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 和 PCLK1 的配置 ---------------------------*/    
  /* 使能 外部高速时钟HSE,RCC_CR_HSEON = ((uint32_t)0x00010000)*/    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待 HSE 准备好,如果超时了,就退出 */
  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(使能预取缓存器) */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

	/* 因为CPU的速度要比FLASH快得多,所以CPU需要等待几个时钟周期,
	具体的寄存器配置我在下面列出了 FLASH_ACR 寄存器的功能,系统时钟为72MHz的时候需要等待2个等待状态*/
    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* 设置 HCLK = SYSCLK,由STM32F10XX时钟系统框图可以看到要 HCLK = SYSCLK,AHB预分频器的分频因子要设为1,即不分频 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; 
      
    /* PCLK2 = HCLK ,PCLK2的时钟频率为72MHz*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK/2 ,PCLK1最大的时钟频率为36MHz*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#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));
    //选择HSE为PLL的时钟源,设置倍频系数为9,此时HSE是8MHz,倍频之后为72MHz
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); 
#endif /* STM32F10X_CL */

    /* 使能PLL时钟 */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL时钟就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择PLL作为系统时钟来源 */
    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
  { /* 如果HSE启动失败,应用程序将有错误的时钟配置。
       用户可以在这里添加一些代码来处理这个错误 */
  }
}

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值