欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32F1 时钟树

程序员文章站 2022-07-04 16:01:32
...

STM32F1 时钟树

参考:《【野火®】零死角玩转STM32—F103指南者》
STM32F1 时钟树

时钟源

  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搭载的外设如下图所示:

STM32F1 时钟树

其它

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((HSEStatus == 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)
	{
		
	}

}