【自学笔记】STM32时钟系统详解

什么是时钟?

时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定CPU速率。片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。

为什么STM32要有多个时钟源呢?

​ STM32本身十分复杂,外设非常多 但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费 并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树。

总括:

​ 1.STM32时钟系统主要目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。

​ 2.系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)

​ 3.时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。

​ 4.一个单片机内提供多个不同的系统时钟,可以适应更多的场合

​ 5.不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。对不同的模块的时钟增加了开启和关闭的功能,可以降低单片机的功耗。

​ 6.STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。 这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因。

STM32的时钟系统框图

img

​ 我们看系统时钟SYSCLK的左边,系统时钟有很多在选择,而左边的部分就是设置系统时钟使用哪个时钟源

系统时钟SYSCLK的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率

从左到右可以简单理解为 各个时钟源–>系统时钟来源的设置–>各个外设时钟的设置

时钟系统
1、各个时钟源(左边部分)

STM32有4个独立时钟源:HSI、HSE、LSI、LSE。

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

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

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

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

其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源而独立使用

HSI高速内部时钟、HSE高速外部时钟、PLL锁相环时钟 这三个经过分频或者倍频,作为系统时钟来使用

PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2.倍频可选择2~16倍,但是其输出频率最大不得超过32 MHz(对于STM32L0系列来说)。通过倍频之后作为系统时钟的时钟源。

我举一个例子,STM32L073RZ的最大时钟源频率为32 MHz,外部晶振(HSE)提供的8 MHz,通过 PLLMul锁相环进行倍频(X8)以及一个PLLDiv(/2)进行分频后得到32 MHz为系统提供系统时钟(SYSCLK)。之后就是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。

或者内部RC振荡器(HSI)为16 MHz进入锁相环 ,通过 PLLMul进行倍频(X2)后得到32 MHz来提供系统时钟。

2、系统时钟

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

1、HSI振荡器时钟

2、HSE振荡器时钟

3、PLL时钟

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TVRmvjDg-1627885064434)(C:\Users\zkhy\AppData\Roaming\Typora\typora-user-images\image-20210730112608589.png)]

3、把时钟信号输出到外部

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UO2U9Q9c-1627885064435)(C:\Users\zkhy\AppData\Roaming\Typora\typora-user-images\image-20210730112747297.png)]

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

4.系统时钟通过AHB分频器给外设提供时钟(右边部分)

​ 从左到右可以理解为 系统时钟–>AHB分频器–>各个外设分频倍频器–>外设时钟的设置

右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各个模块使用,为一下5大模块:

1、内核总线: 送给AHB总线,内核,内存和DMA使用的HCLK时钟。

2、**Tick定时器:**分频后送给Cortex的系统定时器时钟。

3、**I2S总线:**直接送给Cortex的空闲运行时钟FCLK。

4、**APB1外设:**送给APB1分频器,其输出一路提供APB1外设使用(PCLK1,最大32 MHz),另一路送给通用定时器使用,时钟输出提供定时器2-7使用。

5、**APB2外设:**送给APB2分频器,其输出一路提供APB2外设使用(PCLK2,最大32 MHz),另一路送给高级定时器使用。时钟输出提供定时器1和定时器8使用。

RCC相关寄存器

这里我是以STM32L073rz为例:

typedef struct
{
     
  __IO uint32_t CR;            /*!< RCC clock control register,HSI、HSE、CSS、PLL等的使能            Address offset: 0x00 */
  __IO uint32_t ICSCR;         /*!< RCC Internal clock sources calibration register,              Address offset: 0x04 */
  __IO uint32_t CRRCR;         /*!< RCC Clock recovery RC register,                               Address offset: 0x08 */
  __IO uint32_t CFGR;          /*!< RCC Clock configuration register,                             Address offset: 0x0C */
  __IO uint32_t CIER;          /*!< RCC Clock interrupt enable register,                          Address offset: 0x10 */
  __IO uint32_t CIFR;          /*!< RCC Clock interrupt flag register,                            Address offset: 0x14 */
  __IO uint32_t CICR;          /*!< RCC Clock interrupt clear register,                           Address offset: 0x18 */
  __IO uint32_t IOPRSTR;       /*!< RCC IO port reset register,                                   Address offset: 0x1C */
  __IO uint32_t AHBRSTR;       /*!< RCC AHB peripheral reset register,                            Address offset: 0x20 */
  __IO uint32_t APB2RSTR;      /*!< RCC APB2 peripheral reset register,                           Address offset: 0x24 */
  __IO uint32_t APB1RSTR;      /*!< RCC APB1 peripheral reset register,                           Address offset: 0x28 */
  __IO uint32_t IOPENR;        /*!< RCC Clock IO port enable register,                            Address offset: 0x2C */
  __IO uint32_t AHBENR;        /*!< RCC AHB peripheral clock enable register,                     Address offset: 0x30 */
  __IO uint32_t APB2ENR;       /*!< RCC APB2 peripheral enable register,                          Address offset: 0x34 */
  __IO uint32_t APB1ENR;       /*!< RCC APB1 peripheral enable register,                          Address offset: 0x38 */
  __IO uint32_t IOPSMENR;      /*!< RCC IO port clock enable in sleep mode register,              Address offset: 0x3C */
  __IO uint32_t AHBSMENR;      /*!< RCC AHB peripheral clock enable in sleep mode register,       Address offset: 0x40 */
  __IO uint32_t APB2SMENR;     /*!< RCC APB2 peripheral clock enable in sleep mode register,      Address offset: 0x44 */
  __IO uint32_t APB1SMENR;     /*!< RCC APB1 peripheral clock enable in sleep mode register,      Address offset: 0x48 */
  __IO uint32_t CCIPR;         /*!< RCC clock configuration register,                             Address offset: 0x4C */
  __IO uint32_t CSR;           /*!< RCC Control/status register,                                  Address offset: 0x50 */
} RCC_TypeDef;
RCC初始化

这里我使用的是HSE外部时钟,正常使用的时候也是外部时钟,使用HSE时钟,程序设置时钟参数流程:

1、将RCC寄存器重新设置为默认值

2、打开外部高速时钟HSE

3、等待外部高速时钟晶振工作

4、设置AHB时钟

5、设置高速AHB时钟

6、设置低速AHB时钟

7、设置PLL

8、打开PLL

9、等待PLL工作

10、设置系统时钟

11、判断是否PLL是系统时钟

12、打开要是有的外设时钟

代码实现

对RCC的配置函数(使用外部8 MHz晶振)

void RCC_Configuration(void)
{
     
	//----------使用外部RC晶振-----------
	RCC_DeInit();			//初始化为缺省值
	RCC_HSEConfig(RCC_HSE_ON);	//使能外部的高速时钟 
	while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);	//等待外部高速时钟使能就绪
	
	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);	//Enable Prefetch Buffer
	FLASH_SetLatency(FLASH_Latency_2);		//Flash 2 wait state
	
	RCC_HCLKConfig(RCC_SYSCLK_Div1);		//HCLK = SYSCLK
	RCC_PCLK2Config(RCC_HCLK_Div1);			//PCLK2 =  HCLK
	RCC_PCLK1Config(RCC_HCLK_Div2);			//PCLK1 = HCLK/2
	RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);	//PLLCLK = 8MHZ * 9 =72MHZ
	RCC_PLLCmd(ENABLE);			//Enable PLLCLK
 
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);	//Wait till PLLCLK is ready
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);	//Select PLL as system clock
	while(RCC_GetSYSCLKSource()!=0x08);		//Wait till PLL is used as system clock source
	
	//---------打开相应外设时钟--------------------
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能APB2外设的GPIOA的时钟		 
}

!=0x08); //Wait till PLL is used as system clock source

//---------打开相应外设时钟--------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能APB2外设的GPIOA的时钟		 

}


 

你可能感兴趣的:(自学笔记,单片机,嵌入式,stm32)