单片机入门学习八 STM32单片机学习五 时钟系统

单片机学习除了了解该篇 单片机入门学习五 STM32单片机学习二 跑马灯程序衍生出的stm32编程基础 中的基础外,我们还需要有时钟的概念,本篇将记录 stm32的时钟系统。

1、STM32时钟介绍
下面这幅图时stm32的时钟系统框图
单片机入门学习八 STM32单片机学习五 时钟系统_第1张图片
1)蓝底框表示 时钟源,即:
①HSI是高速内部时钟,RC振荡器,频率为8MHz。
②HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
③LSI是低速内部时钟,RC振荡器,频率为40kHz。(WDG看门狗 使用该时钟源)
④LSE是低速外部时钟,接频率为32.768kHz的石英晶体。(RTC实时时钟 使用该时钟源)
⑤PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
其中HSE和LSE是通过单片机外部的晶振输入的,一共四个管脚,HSE的输入管脚是OSC_IN和OSC_OUT(通常为8M),
LSE的输入管脚对应的引脚为OSC32_IN和OSC32_OUT(32.768kHz)
2)梯形表示 选择器,例如:
单片机入门学习八 STM32单片机学习五 时钟系统_第2张图片
梯形表示 SYSCLK系统时钟的来源可以使HSI RC、PLLCLK、HSE Osc(即HSI振荡器时钟、HSE振荡器时钟、PLL时钟)
3)绿色方框 表示 预分频器(prescaler)
4)该图片如何看,比如下图:
单片机入门学习八 STM32单片机学习五 时钟系统_第3张图片
按照上图深红色 的路线来解释:PLL的时钟源 经过前面的选择器 假设为8MHz,经过PLL 9倍频后 PLLCLK的频率为72MHz,则经过选择器 SYSCLK(系统时钟)频率为72MHz,经过AHB分频器 1分频后 HCLK输出频率72MHz,经过APB1分频器 2分频后 PCLK1频率为36MHz; 经过APB2分频器 1分频后 PCLK2频率为72MHz。
5)时钟输出MCO脚(PA8),可以选择PLL输出的2分频、HSI、HSE或者系统时钟。
单片机入门学习八 STM32单片机学习五 时钟系统_第4张图片
6)任何一个外设在使用之前,必须首先使能其相应的时钟。
7)需要记住几个重要的时钟
- SYSCLK(系统时钟)
- AHB总线时钟
- APB1总线时钟(低速),速度最高到36MHz
- APB2总线时钟(高速),速度最高到72MHz
- PLL时钟
下面贴一张《STM32中文手册》中的时钟图,该图和上面的图表示的意思是一致的,我们看看官方是如何展示 时钟框图的。
单片机入门学习八 STM32单片机学习五 时钟系统_第5张图片

2、(时钟控制)RCC寄存器

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;       //控制状态寄存器
} RCC_TypeDef;

上面是RCC寄存器的结构体定义,结构体中的每个变量的每一位代表什么需要我们参考《STM32中文手册》第6章的6.3小节 RCC寄存器描述来了解,现仅对一个变量CR贴出 参考手册 的描述,其余的就不列出了,参考手册即可。
单片机入门学习八 STM32单片机学习五 时钟系统_第6张图片

3、系统时钟初始化
上面仅仅是对 时钟控制器 做了一个概念性的介绍,在编写程序时我们一般不直接操作 RCC_TypeDef结构体,而是调用相应的库函数来编程。
在此我们先看一下 库函数中 系统默认如何初始化这些 寄存器的,我们先看一段汇编程序,我们知道c中默认的程序入口是main函数,那main函数的如何调用的呢,我们先来看如下程序(该程序在startup_stm32f10x_hd.s中可以找到):

; Reset handler
Reset_Handler   PROC
EXPORT  Reset_Handler             [WEAK]
IMPORT  __main
IMPORT  SystemInit
LDR     R0, =SystemInit
BLX     R0               
LDR     R0, =__main
BX      R0
ENDP

从上面的程序中可以看出 在main函数调用前,调用了SystemInit函数,该函数的定义可以在system_stm32f10x.c中找到,源码如下:

#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

/*!< 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

/*******************************************************************************
*  Clock Definitions
*******************************************************************************/
#ifdef SYSCLK_FREQ_HSE
  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
  uint32_t SystemCoreClock         = HSI_VALUE;        /*!< System Clock Frequency (Core Clock) */
#endif

__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};

static void SetSysClock(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;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   

  /* 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;

#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 

  /* 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 
}

/**
 * @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) */ 
}

1)从上面代码逐行往下看,我们知道我们前面的程序 定义的宏定义是 STM32F10X_HD,如下图宏定义
2)从而在初始化器确定了系统时钟频率为(72MHz):‘#define SYSCLK_FREQ_72MHz 72000000’
初始化智慧的状态为:

  • SYSCLK 72MHz
  • AHB 72MHz
  • PCLK1 36MHz
  • PCLK2 72MHz
  • PLL 72MHz

3)SystemInit()函数的第一行代码RCC->CR |= (uint32_t)0x00000001;我们查手册 CR寄存器第一位置1,表示开启8MHz内部振荡器,后续的代码阅读如该句,都需要参照手册 来理解,在此不再说明。
4)初始化之后可以通过变量SystemCoreClock获取系统变量。如果SYSCLK=72MHz,那么变量SystemCoreClock=72000000。

4、RCC寄存器配置库函数
上面了解了 stm32默认给我们配置的是 什么样的时钟源,若我们想自定义,则需要借助系统库函数来进行修改,则我需要用到 stm32f10x_rcc.h里定义的库函数

  • 时钟使能配置:
    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()…

你可能感兴趣的:(楼宇自控,单片机,单片机入门学习)