STM32F1 时钟树

STM32F1 时钟树

参考:《【野火®】零死角玩转STM32—F103指南者》
在这里插入图片描述

时钟源

  1. HSI:高速内部时钟,RC振荡器,频率为8MHz
  2. HSE:高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz
  3. LSI:低速内部时钟,RC振荡器,频率为40kHz
  4. LSE:低速外部时钟,接频率为32.768kHz的石英晶体
  • LSI可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/待机模式下自动唤醒系统。LSE也可用来通过程序选择驱动RTC。

  • 内部即指芯片已经集成,外部即指需要设计PCB时接入

  • 锁相环:这个东西可以将输入频率进行放大然后输出,比如说输入1MHz,设置倍频为3倍,最后就能输出3MHz的信号。STM32的锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

时钟配置

主要

SYSCLK:系统时钟
HCLK:AHB总线时钟
PCLK2:APB2总线时钟
PCLK1:APB1总线时钟

库函数的标准配置:PCLK2 = HCLK = SYSCLK = PLLCLK = 72M,PCLK1 = HCLK/2 = 36M
APB1和APB2搭载的外设如下图所示:

在这里插入图片描述

其它

USB时钟
USB 时钟是由 PLLCLK 经过 USB 预分频器得到,分频因子可以是:[1,1.5],具体的由时钟配置寄存器 CFGR 的位 22:USBPRE 配置。USB 的时钟最高是 48M,根据分频因子反推过来算,PLLCLK 只能是 48M 或者是 72M。一般我们设置 PLLCLK=72M,USBCLK=48M。USB 对时钟要求比较高,所以 PLLCLK 只能是由 HSE 倍频得到,不能使用 HSI 倍频。

Cortex 系统时钟
Cortex 系统时钟由 HCLK 8 分频得到,等于 9M,Cortex 系统时钟用来驱动内核的系统定时器 SysTick,SysTick 一般用于操作系统的时钟节拍,也可以用做普通的定时。

ADC 时钟
ADC 时钟由 PCLK2 经过 ADC 预分频器得到,分频因子可以是[2,4,6,8],具体的由时钟配置寄存器 CFGR 的位 15-14:ADCPRE[1:0]决定。很奇怪的是怎么没有 1 分频。ADC时钟最高只能是 14M,如果采样周期设置成最短的 1.5 个周期的话,ADC 的转换时间可以达到最短的 1us。如果真要达到最短的转换时间 1us 的话,那 ADC 的时钟就得是 14M,反推 PCLK2 的时钟只能是:28M、56M、84M、112M,鉴于 PCLK2 最高是 72M,所以只能取 28M 和 56M。

RTC 时钟、独立看门狗时钟
RTC 时钟可由 HSE/128 分频得到,也可由低速外部时钟信号 LSE 提供,频率为32.768KHZ,也可由低速内部时钟信号 HSI 提供,具体选用哪个时钟由备份域控制寄存器BDCR 的位 9-8:RTCSEL[1:0]配置。独立看门狗的时钟由 LSI 提供,且只能是由 LSI 提供,LSI 是低速的内部时钟信号,频率为 30~60KHZ 直接不等,一般取 40KHZ。

MCO 时钟输出
MCO 是 microcontroller clock output 的缩写,是微控制器时钟输出引脚,在 STM32 F1系列中 由 PA8 复用所得,主要作用是可以对外提供时钟,相当于一个有源晶振。MCO 的时钟来源可以是:PLLCLK/2、HSI、HSE、SYSCLK,具体选哪个由时钟配置寄存器CFGR 的位 26-24:MCO[2:0]决定。除了对外提供时钟这个作用之外,我们还可以通过示波器监控 MCO 引脚的时钟输出来验证我们的系统时钟配置是否正确。

基于标准库的设置代码

使用标准库的模板工程,在系统启动的时候,statup_stm32f10x_hd.s 已经调用 SystemInit()函数把系统时钟初始化成 72MHZ,SystemInit()在库文件:system_stm32f10x.c 中定义。然后再进入main函数。

如果我们想把系统时钟设置低一点或者超频的话,可以修改底层的库文件,即改动SystemInit()函数。但是为了维持库的完整性,可以在按照标准库的方法启动后进入main函数中时,再自己写个时钟初始化函数将系统时钟重新配置。

HSI 设置系统时钟函数跟 HSE 设置系统时钟函数在原理上是一样的,有一个区别的地方就是,HSI 必须 2 分频之后才能作为 PLL 的时钟来源,所以使用 HSI 时,最大的系统时钟 SYSCLK 只能是 HSI/216=416=64MHZ。

 void HSE_SetSysClock(uint32_t pllmul)
{
    volatile uint32_t StartUpCounter = 0, HSEStartUpStatus = 0;
    RCC_DeInit();         //重设RCC寄存器为缺省值
    RCC_HSEConfig(RCC_HSE_ON);   //使能HSE
    
    do
  	{
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    StartUpCounter++;  
  	} while((HSEStartUpStatus == 0) && (StartUpCounter != 9));//等待 HSE 启动稳定
     
    if ( RCC_WaitForHSEStartUp() != 0)  //等待使能成功
  	{    	
//-----------------------------------------------------------------//
// 这两句是操作 FLASH 闪存用到的,如果不操作 FLASH,这两个注释掉也没影响
// 使能 FLASH 预存取缓冲区
	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
// SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
// 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
// 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M
	FLASH_SetLatency(FLASH_Latency_2);
//-----------------------------------------------------------------//
     
    // AHB预分频因子设置为1分频,HCLK = SYSCLK 
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    // APB2预分频因子设置为1分频,PCLK2 = HCLK
    RCC_PCLK2Config(RCC_HCLK_Div1); 
    // APB1预分频因子设置为1分频,PCLK1 = HCLK/2 
    RCC_PCLK1Config(RCC_HCLK_Div2);

//-----------------设置各种频率主要就是在这里设置-------------------//
    // 设置PLL时钟来源为HSE,设置PLL倍频因子
     // PLLCLK = 8MHz * pllmul
	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);
//------------------------------------------------------------------//

    // 开启PLL 
    RCC_PLLCmd(ENABLE);
    // 等待 PLL稳定
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    // 读取时钟切换状态位,确保PLLCLK被选为系统时钟
    while (RCC_GetSYSCLKSource() != 0x08);
       
   }
    else
    {
       // 当HSE开启失败或者故障的时候,单片机会自动把HSI设置为系统时钟,HSI是内部的高速时钟,8MHZ
       // 如果HSE开启失败,可在这里添加出错的代码处理
    }
    
}

MCO配置

/*
 * 初始化MCO引脚PA8
 * 在F1系列中MCO引脚只有一个,即PA8,在F4系列中,MCO引脚会有两个
 */
void MCO_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// 开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 选择GPIO8引脚
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	
	//设置为复用功能推挽输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	
	//设置IO的翻转速率为50M
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	// 初始化GPIOA8
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

int main(void)
{	
	
	HSE_SetSysClock(RCC_PLLMul_9);
	MCO_GPIO_Config();// MCO 引脚初始化
		
	RCC_MCOConfig(RCC_MCO_SYSCLK);		     // 72M  
	
	while (1)
	{
		
	}

}

猜你喜欢

转载自blog.csdn.net/lblmlms/article/details/109165346