当前位置: 移动技术网 > 网络运营>服务器>Linux > 【STM32学习笔记】时钟的配置

【STM32学习笔记】时钟的配置

2020年08月12日  | 移动技术网网络运营  | 我要评论
时钟树简单总结一下:​PLLCLK的来源有三个,HSE、HSE/2、HSI/2,一般选 HSE = 8M​SYSCLK(系统时钟)的来源有三个,PLLCLK(锁相环)、HSE、HEI,一般选 PLLCLK * 9 = 72M​AHB总线上的时钟 HCLK = SYSCLK = 72M​APB1总线上的时钟 PCLK1 = HCLK/2 = 36M​APB2总线上的时钟 PCLK2 = HCLK = 72M官方固件库的时钟配置(通过寄存器)static void SetS

时钟树

在这里插入图片描述

简单总结一下:

​ PLLCLK的来源有三个,HSE、HSE/2、HSI/2,一般选 HSE = 8M

​ SYSCLK(系统时钟)的来源有三个,PLLCLK(锁相环)、HSE、HEI,一般选 PLLCLK * 9 = 72M

​ AHB总线上的时钟 HCLK = SYSCLK = 72M

​ APB1总线上的时钟 PCLK1 = HCLK/2 = 36M

​ APB2总线上的时钟 PCLK2 = HCLK = 72M

官方固件库的时钟配置(通过寄存器)

static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* 使能 HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪并做超时处理 */
  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;
  }  

  // 如果HSE启动成功,程序则继续往下执行
  if (HSEStatus == (uint32_t)0x01)
  {
    // 使能预取指
    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 = 72M
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    // PCLK2 = HCLK = 72M 
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    // PCLK1 = HCLK/2 = 36M
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    
    //  锁相环配置: PLLCLK = HSE * 9 = 72 MHz 
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

    // 使能 PLL 
    RCC->CR |= RCC_CR_PLLON;

    // 等待PLL稳定 
    while((RCC->CR & RCC_CR_PLLRDY) == 0);  
    // 选择PLLCLK作为系统时钟
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    // 等待PLLCLK切换为系统时钟 
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08);
      
  }
  else
  { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
  }
}

自己写的时钟配置(通过固件库中已封装的函数)

可改变倍频,实现不同频率锁相环,从而改变系统时钟的频率

#include "bsp_rccclkconfig.h"

void HSE_SetSysClk(uint32_t RCC_PLLMul_x){
	
	ErrorStatus HSEStatus; /* ErrorStatus RCC_WaitForHSEStartUp(void); */
	
	//寄存器复位
	RCC_DeInit();
	
	//使能 HSE
	RCC_HSEConfig(RCC_HSE_ON);
	//等待HSE稳定
	HSEStatus=RCC_WaitForHSEStartUp();
	
	if(HSEStatus==SUCCESS){
		
		// 使能预取指
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
		// Flash 2 wait state 
		FLASH_SetLatency(FLASH_Latency_2);
		
		// HCLK = SYSCLK = 72M
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
    // PCLK1 = HCLK = 36M
		RCC_PCLK1Config(RCC_HCLK_Div2);
    // PCLK2 = HCLK = 72M 
		RCC_PCLK2Config(RCC_HCLK_Div1);
		
		//  锁相环(PLL)配置: PLLCLK = HSE * x = ?? MHz 
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
		// 使能PLL
		RCC_PLLCmd(ENABLE);
		// 等待PLL稳定
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
		
		// 选择系统时钟
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		// 等待PLLCLK切换为系统时钟 
		while(RCC_GetSYSCLKSource() != 0x08);
		
	}
	
	else{
		/* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
	}
	
}

void HSI_SetSysClk(uint32_t RCC_PLLMul_x){
	
	__IO uint32_t HSIStatus; /* ErrorStatus RCC_WaitForHSEStartUp(void); */
	
	//寄存器复位
	RCC_DeInit();
	
	//使能 HSI
	 RCC_HSICmd(ENABLE);
	//等待HSI稳定
	HSIStatus = RCC->CR & RCC_CR_HSIRDY;
	
	if(HSIStatus==SUCCESS){
		
		// 使能预取指
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
		// Flash 2 wait state 
		FLASH_SetLatency(FLASH_Latency_2);
		
		// HCLK = SYSCLK = 72M
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
		// PCLK1 = HCLK = 36M
		RCC_PCLK1Config(RCC_HCLK_Div2);
    // PCLK2 = HCLK = 72M 
		RCC_PCLK2Config(RCC_HCLK_Div1);
    
		//  锁相环(PLL)配置: PLLCLK = HSI * x = ?? MHz 
		RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
		// 使能PLL
		RCC_PLLCmd(ENABLE);
		// 等待PLL稳定
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
		
		// 选择系统时钟
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		// 等待PLLCLK切换为系统时钟 
		while(RCC_GetSYSCLKSource() != 0x08);
		
	}
	
	else{
		/* 如果HSI 启动失败,用户可以在这里添加处理错误的代码 */
	}
	
}


//MCO 输出初始化
void MCO_GPIO_Config(void){
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
}

/** 通过 MCO 输出不同源的时钟频率,可连接示波器观察频率
  *下列函数为官方固件库中已封装函数,在main中直接调用即可
  *如:输出系统时钟的频率:RCC_MCOConfig(RCC_MCO_SYSCLK);
  */

/**
  * @brief  Selects the clock source to output on MCO pin.
  * @param  RCC_MCO: specifies the clock source to output.       
  *     @arg RCC_MCO_NoClock: No clock selected
  *     @arg RCC_MCO_SYSCLK: System clock selected
  *     @arg RCC_MCO_HSI: HSI oscillator clock selected
  *     @arg RCC_MCO_HSE: HSE oscillator clock selected
  *     @arg RCC_MCO_PLLCLK_Div2: PLL clock divided by 2 selected
  */
void RCC_MCOConfig(uint8_t RCC_MCO)
{
  /* Check the parameters */
  assert_param(IS_RCC_MCO(RCC_MCO));

  /* Perform Byte access to MCO bits to select the MCO source */
  *(__IO uint8_t *) CFGR_BYTE4_ADDRESS = RCC_MCO;
}

本文地址:https://blog.csdn.net/Brave_Runer/article/details/107920262

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网