stm32F1xx时钟配置分析总结

目录

前言

正如万物的生长、发展离不开时间、节律一样,芯片的工作也离不开时钟的驱动,本文总结stm32f1xx的时钟系统介绍以及时钟配置时的步骤、寄存器操作,基于标准库函数;

时钟树

上图为stm32f1xx的参考手册中的时钟树图,图中梯形框表示复用选择,方形框表示倍频或分频或时钟源;

stm32中的时钟包括HSI、HSE、LSI、LSE(内部高速振动器、外部高速振荡器、内部低速振荡器、外部低速振荡器)、PLL(锁相环);

其中HSI、HSE、LSI、LSE 可以直接提供时钟,而PLL需要以HSE、HSI为直接源或者以HSE为源并通过MCU内部分频倍频处理后得到PLL;

sysclk系统时钟也可以直接选择HSI、HSE为源头,不过这些频率都比较小在有PLL模块的芯片一般会使用PLL获得一个高频率作为系统时钟;

系统时钟作为AHB总线的输入时钟源,经过AHB总线分频后的输出作为APB1和APB2的时钟源,在时钟树节点中节点可以以某个时钟为源且可以对源的频率进行分频或者倍频给下一级,直到最终的时钟源使用者;结合以下的系统架构图方便理解:

配置列举

下面以系统时钟和uart外设时钟为例说明时钟配置

系统时钟

stm32f1xx系列最高主频为72Mhz,以配置为72Mhz说明具体配置过程:

1、时钟配置外设RCC的寄存器如下

c 复制代码
typedef struct
{
  __IO uint32_t CR; //时钟控制寄存器,主要对HSE、HSI、PLL的开关控制和状态查询
  __IO uint32_t CFGR; //时钟配置寄存器,对时钟源的选择配置、分频倍频的配置
  __IO uint32_t CIR;  //时钟中断寄存器,用于清除时钟中断标志和包括表示时钟中断的位域
  __IO uint32_t APB2RSTR;  //APB2外设复位寄存器
  __IO uint32_t APB1RSTR;  //APB1外设复位寄存器
  __IO uint32_t AHBENR; //使能AHB上外设的时钟
  __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;

2、配置函数调用过程

Reset_Handler【startup_stm32f10x_hd.s】 -> SystemInit【system_stm32f10x.c】 -> SetSysClock【system_stm32f10x.c】-> SetSysClockTo72【system_stm32f10x.c】 = 产生72Mhz时钟

3、函数说明

SystemInit 中有英文注释可以对照手册的对寄存器的说明进行理解,主要是在进行时钟配置前做一些时钟复位的工作 ;

SetSysClock为一个中间函数会根据目标系统时钟宏选择调用哪个函数,这里调用SetSysClockTo72;

SetSysClock函数为时钟配置主要函数

c 复制代码
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */
  //bit16 使能选择HSE外部高度振荡器,这里为8Mhz    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON); 
  /* Wait till HSE is ready and if Time out is reached exit */
  //查询CR的bit17判断振荡器是否准备好或者有信号
  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) //HSE振荡器正常
  {
    /* 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 */
    //CFGR寄存器的bit7~bit4配置AHB对系统时钟不进行分频
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    /* PCLK2 = HCLK */
    //CFGR寄存器的bit13~bit11配置APB2对AHB过来的时钟不进行分频
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    //CFGR寄存器的bit10~bit8配置APB1对AHB过来的时钟进行二分频
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    
#else    
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    //清除bit16:RCC_CFGR_PLLSRC PLL时钟源是HSI
    //清除bit17:RCC_CFGR_PLLXTPRE 对HSE时钟不分频,PREDIV1从时钟树中看到它表示HSE后面的分频器
    //清除bit21~bit18 PLL倍频系数先清0 不倍频
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
    
    //配置bit16:RCC_CFGR_PLLSRC_HSE 选择HSE作为PLL的时钟源
    //配置bit21~bit18 对PLL时钟倍频9 得到PLLCLK 为 8Mhz*9=72Mhz
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* Enable PLL */
    //使能CR的bit24 PLL使能
    RCC->CR |= RCC_CR_PLLON;
    /* Wait till PLL is ready */
    //判断bit25 PLL时钟是否锁定
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* Select PLL as system clock source */
    //清除bit1~bit0,随后设置为0x02表示将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 */
    //bit3~bit2 判断是否切换为PLL作为系统时钟
    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 */
  }
}

TIMER时钟

相关推荐
m0_739312873 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件
嵌入式小章3 小时前
基于STM32的实时时钟(RTC)教学
stm32·嵌入式硬件·实时音视频
徐嵌4 小时前
STM32项目---水质水位检测
stm32·单片机·嵌入式硬件
徐嵌4 小时前
STM32项目---畜牧定位器
c语言·stm32·单片机·物联网·iot
stm32发烧友5 小时前
基于STM32的智能家居环境监测系统设计
stm32·嵌入式硬件·智能家居
hairenjing112313 小时前
使用 Mac 数据恢复从 iPhoto 图库中恢复照片
windows·stm32·嵌入式硬件·macos·word
u01015265816 小时前
STM32F103C8T6学习笔记2--LED流水灯与蜂鸣器
笔记·stm32·学习
北京迅为21 小时前
【北京迅为】《STM32MP157开发板嵌入式开发指南》-第七十八章 Qt控制硬件
linux·stm32·单片机·嵌入式硬件
llhm1 天前
stm32 踩坑笔记
stm32·单片机·嵌入式硬件
charlie1145141911 天前
从0开始的STM32之旅8 串口通信(II)
stm32·单片机·嵌入式硬件·c·串口通信