RCC——配置系统时钟

前言

这次讲解RCC这个外设,即复位与时钟控制,主要讲解时钟。时钟像是人的心脏,所有的外设如果想工作,都必须要开启相应的时钟,虽然系统时钟早已被汇编语言设定为72M,但我们也可以通过写程序改变系统时钟甚至超频

时钟树及讲解

在这里插入图片描述
以上图片即为时钟树,它上面包含了stm32f10x的所有时钟配置,下面,我将会对它进行讲解。
首先是HSE时钟,即高速的外部时钟,来源为外部晶振(4-16M),通常为8M。
还有HSI时钟,高速的内部时钟,大小为8M,当HSE故障时,系统时钟自动切换到HSI,直到HS启动成功,但精度比HSE低。
PLLCLK:锁相环时钟,它有四种情况

1.锁相环时钟为HSI
2. HSI频率除2后经过倍频后得到PLLCLK
3. HSE倍频得到PLLCLK
4. HSE频率除2后倍频得到PLLCLK
(注意:PLLCLK源头使用HSI/2时,PLLMUL最大只能是16,这个时候PLLCLK最大只能是64M)
得到PLLCLK时钟后,经过AHB预分频器为单片机外设提供时钟,值得注意的是APB1与APB2上也有预分频器,为挂载在APB1和APB2的外设提供时钟,APB1和APB2的时钟成为PCLK1时钟和PCLK2时钟
PCLK1时钟:APB1低速总线时钟,最高为36M
PCLK2时钟:APB2高速总线时钟,最高为72M
RTC时钟:为芯片内部的PTC外设提供时钟
来源有HSE_RTC(HSE分频得到),LSE(低速外部时钟),LSI(低速内部时钟)
MCO时钟输出:微控制器时钟输出引脚,由PA8复用所得
来源为PLLCLK/2,HSE,HSI,SYSCLK
我们在改变单片机的时钟后用MCO实时监测

系统时钟配置函数SetsysClockTo72()讲解

虽然对时钟树有一定了解,但改变系统时钟仍有很多细节需要优化,因此我们可以通过分析固件库函数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->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=36M */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#else    
    /*  锁相环配置: 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);
#endif /* STM32F10X_CL */

    /*使能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启动失败,用户可以在这里添加处理错误的代码*/
  }
} 

操作寄存器

时钟控制寄存器(RCC_CR)

在这里插入图片描述
在这里插入图片描述

时钟配置寄存器(RCC_CFGR)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码编写:(HSE配置系统时钟)

改变频率

步骤与上个代码类似只要步骤相同即可,不同的是上个代码直接操作寄存器,而我们要使用固件库编写代码

//使用HSE配置系统时钟
void HSE_SetSysClk(uint32_t RCC_PLLMul_x)
{
	ErrorStatus  HSEStatus;
	
	RCC_DeInit();//把RCC寄存器复位
	RCC_HSEConfig(RCC_HSE_ON);//使能HSE(外部时钟)
	HSEStatus=RCC_WaitForHSEStartUp();
	if(HSEStatus==SUCCESS)
	{
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//使能预取指
		FLASH_SetLatency(FLASH_Latency_2);//设置两个等待
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
        RCC_PCLK1Config(RCC_HCLK_Div2);
        RCC_PCLK2Config(RCC_HCLK_Div1);
	    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);//配置PLLCLK=HSE*RCC_PLLMul_x
       RCC_PLLCmd(ENABLE);//使能PLL
		
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET );//等待PLL稳定
	    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//选择系统时钟
		while(RCC_GetSYSCLKSource()!=0x08);
	}
	else{
/*如果HSE启动失败,用户可以在这里添加处理错误的代码*/
	}
}

当RCC_PLLMul_x为RCC_PLLMul_10时
PCCLK的频率就变为80M

那我们如何检测呢?
这便需要MCO引脚

检测频率

先设置MCO对应的PA_8为推挽输出模式

void MCO_GPIO_Config()//MCO对应的GPIO口为PA8
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIOA时钟
	
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);//配置GPIOA
}

然后将MCO的时钟设为SYSCLK,系统时钟已选为PLLCLK,所以检测的就是PLLCLK。
同理也可以用HSI配置系统时钟

代码编写(同理也可以用HSI配置系统时钟)

//使用HSI配置系统时钟
void HSI_SetSysClk(uint32_t RCC_PLLMul_x)
{
	__IO uint32_t  HSIStatus = 0;
	
	RCC_DeInit();//把RCC寄存器复位
	RCC_HSICmd(ENABLE);//使能HSI(内部时钟)
	HSIStatus = RCC->CR & RCC_CR_HSIRDY;
	if(HSIStatus==RCC_CR_HSIRDY)
	{
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//使能预取指
		FLASH_SetLatency(FLASH_Latency_2);//设置两个等待
		
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_PCLK2Config(RCC_HCLK_Div1);
	  RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);//配置PLLCLK=HSE*RCC_PLLMul_x
    RCC_PLLCmd(ENABLE);//使能PLL
		
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET );//等待PLL稳定
	  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//选择系统时钟
		while(RCC_GetSYSCLKSource()!=0x08);
	}
	else{
	/* 如果HSE启动失败,用户可以在这里添加处理错误的代码*/
	}
}

至此,关于时钟的全部代码已全部写完,有条件的同学可以尝试用示波器接PA8引脚观察MCO输出的频率是否发生变化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值