RCC——系统时钟函数分析时钟的配置流程和自己动手写时钟配置函数配置时钟,实现超频

 下面是SystemInit(void)函数的源代码:重点和时钟配置有关的是SetSysClock()函数

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* 打开 HSION bit,置为1即为打开 */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL            //互联型芯片为105xx和107xx系列我们是hd高密度系列
  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 
}

下面是对于其中一个SetSysClockTo72()函数的分析,得出时钟配置的流程

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;    

 
    /* AHB总线的时钟预分频因子 72MHZ*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* APB2总线时钟预分频因子 72MHZ*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* APB1总线时钟预分频因子 36MHZ*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;


    /*  PLL锁相环倍频因子和输入选择为HSE HSE*9=72MHZ */
    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启动失败,用户可以在这里添加处理错误的代码*/
  }
}
#endif

总结:

时钟配置流程

  • 开启时钟并等待就绪
  • 若时钟异常就退出,执行用户可以自行编写异常处理的代码
  • 开启正常,先配置相关总线的预分频系数
  • 最后选择系统时钟是PLL,还是HSI或者HSE,让外设得到时钟

时钟配置分析(以HSE倍频得到PLLCLK作为系统时钟为例)

  • 开启HSE时钟
  • 等待HSE时钟就绪(因为时钟起振等原因,需要等待一段时间时钟稳定)
  • HSE状态开启正常就继续,异常就转为异常处理
  • HSE正常,设置AHB 、APB1和APB2总线的预分频因子
  • 选择PLL的时钟源为HSE和倍频因子
  • 开启PLL时钟并等待就绪
  • 选择PLLCLK作为系统时钟

其它时钟配置和MCO检测时钟输出

针对上面的分析,自己可以为了保证原来库文件的完整性,建议不要自己动手修改其中的库文件代码,我这里手动新建文件和自己编写函数实现其他时钟的配置以及MCO检查时钟输出

下面是我编写的时钟配置函数:

#include "bsp_rcc_config.h"


void HSE_SetSysClk(uint32_t RCC_PLLMul_x)
{
	ErrorStatus HSEStatus;        //这是一个类型参数,其中原来的库文件中有定义typedef enum 
                                  //  {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
	
	RCC_DeInit();                 //记住如果要修改时钟配置,要把默认的时钟参数恢复为默认状态
	
	RCC_HSEConfig(RCC_HSE_ON);    //按照时钟配置流程,先打开时钟源,我这里还是以HSE为例
	HSEStatus	= RCC_WaitForHSEStartUp();    //等待HSE就绪
	
	if(HSEStatus == SUCCESS)         //如果HSE就绪成功,SUCCESS库文件中定义了ErrorStatus参数
	{		//使能预取指
			FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);    
			FLASH_SetLatency( FLASH_Latency_2);//这里是FLASH编程的知识,48-72MHZ等待两个状态
			
      RCC_HCLKConfig( RCC_SYSCLK_Div1);    //AHB和APB1和APB2的预分频因子
      RCC_PCLK1Config( RCC_HCLK_Div2);
      RCC_PCLK2Config( RCC_HCLK_Div1);
		
		  RCC_PLLConfig(RCC_PLLSource_HSE_Div1,  RCC_PLLMul_x);    //选择HSE作为PLL的输入 
                                                                      和倍频因子为形参
		
      RCC_PLLCmd(ENABLE);                //PLL使能打开
		
			while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );    //等待PLLCLK就绪
		
		  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //选择SYSCLK时钟来源为PLL输出的PLLCLK
			while(RCC_GetSYSCLKSource() != 0x08 );        等待SYSCLK就绪
			
			
	}
	else                    //时钟就绪失败
	{
	
	
	}

}

void MCO_GPIO_Config(void)            //MCO复用为时钟输出数据手册知道是PA8的复用功能
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, 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(GPIOA, &GPIO_InitStruct);            //这是我随便写的一个灯的亮灭的代码
	 GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_Out_PP;
	 GPIO_InitStruct.GPIO_Pin	=	GPIO_Pin_1;
	 GPIO_Init(GPIOB, &GPIO_InitStruct);
}

头文件:

#ifndef __BSP_RCC_CONFIG_H
#define __BSP_RCC_CONFIG_H

#include "stm32f10x.h"

#define ON 1
#define OFF 0 

#define LED(A) if(A) GPIO_ResetBits(GPIOB,GPIO_Pin_1);\
								else GPIO_SetBits(GPIOB,GPIO_Pin_1)

void HSE_SetSysClk(uint32_t RCC_PLLMul_x);
void MCO_GPIO_Config(void);

#endif

main.c函数

#include "stm32f10x.h"
#include "bsp_rcc_config.h"
void delay(uint32_t count)
{
	for(;count!=0;count--);

}
int main(void)
{
	HSE_SetSysClk(RCC_PLLMul_9);  //RCC_PLLMul_x的x可以是2-16对应的倍频因子,
                                    我这是9默认为8*9=72MHZ
	MCO_GPIO_Config();
	RCC_MCOConfig(RCC_MCO_SYSCLK);
	
	while(1)
	{
		LED(ON);
		delay(0xFFFFF);
		LED(OFF);
		delay(0xFFFFF);
	}
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值