2021-06-14 STM32F103 RCC 输出 使用固件库

本文展示了STM32 RCC 初始操作


前言

这里只讲解核心部分的代码,有些变量的设置,头文件的包含等可能不会涉及到,完整的代码请参考本章配套的工程。 为了使工程更加有条理,我们把 LED 灯控制相关的代码独立分开存储,方便以后移植。 在“工程模板”之上新建“RCC_book.c”及“RCC_book.h”文件以及之前的 “Led_book.c”及“Led_book.h”文件

完整代码

一、 编程要点

编程要点对应着时钟树图中的序号。 1、开启 HSE/HSI ,并等待 HSE/HSI 稳定 2、设置 AHB、APB2、APB1 的预分频因子 3、设置 PLL 的时钟来源,和 PLL 的倍频因子,设置各种频率主要就是在这里设置 4、开启 PLL,并等待 PLL 稳定 5、把 PLLCK 切换为系统时钟 SYSCLK 6、读取时钟切换状态位,确保 PLLCLK 被选为系统时钟

二、使用步骤

1.理解原理图

在这里插入图片描述
代码如下:
: STM32F103ZET6 输出口为PB5低电平点有效
: STM32F103ZET6 MCO输出口为PA8

2.建立LED输出的 头文件 RCC_book.h

代码如下(示例):

#ifndef  __RCC_BOOK_H_
#define  __RCC_BOOK_H_

#include "stm32f10x.h"
 
#define   RCC_OUT_GPIO_Port     GPIOA                 //GPIO Point
#define   RCC_OUT_GPIO_Clock    RCC_APB2Periph_GPIOA  //GPIO clock
#define   RCC_OUT_GPIO_Pin      GPIO_Pin_8             
#define   RCC_OUT_GPIO_Pin_Bit  8
#define   RCC_OUT_GPIO_Modle    GPIO_Mode_AF_PP
#define   RCC_OUT_GPIO_Speed    GPIO_Speed_10MHz

void  fn_HRCC_SetSystic( uint32_t  _RCC_PLLMul_x ); //高频设置
void  fn_IRCC_SetSystic( uint32_t  _RCC_PLLMul_x ); //低频设置
void  fn_MCO_GPIO_Config(void);
#endif

3.建立LED输出的 头文件 RCC_book.c

代码如下(示例):

#include  "RCC_book.h"

/************************************************************
* @brief  
* void  fn_HRCC_SetSystic( uint32_t  _RCC_PLLMul_x );
* @param  
* @retval 
*************************************************************/ 
void  fn_HRCC_SetSystic( uint32_t  _RCC_PLLMul_x ){
    
    
  __IO  uint32_t  HSEStatus = 0;
  /* SYSCLK , HCLK , PCLK2 and PCLK1 cnfiguration */
  RCC_DeInit();
  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);
  /* wait till HSE is ready and if Time Out is reached exit*/
  HSEStatus = RCC_WaitForHSEStartUp();
  if(HSEStatus == SUCCESS){
    
    
    // Enable Prefetch Buffer  缓冲区可开启
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    // Flash 2 wait state 
    FLASH_SetLatency(FLASH_Latency_2);
    // 这些位表示SYSCLK(系统时钟)周期与闪存访问的比例
    // SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
    // 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
    // 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
    // 0:0 < SYSCLK <= 24M
    // 1:24< SYSCLK <= 48M
    // 2:48< SYSCLK <= 72M */
    
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    /* HCLK = SYSCLK */     //AHB预分频 (AHB Prescaler) 
    RCC_PCLK1Config(RCC_HCLK_Div2);
    /* PCLK1 = HCLK */     //低速APB预分频(APB1) (APB low-speed prescaler (APB1))   
    RCC_PCLK2Config(RCC_HCLK_Div1);
    /* PCLK1 = HCLK */     //低速APB预分频(APB1) (APB low-speed prescaler (APB1))   
  
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1 ,_RCC_PLLMul_x);
    RCC_PLLCmd(ENABLE);
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz 
    //  PLLSRC: PLL输入时钟源 (PLL entry clock source)
    //  RCC_PLLSource_HSE_Div1 RCC_PLLSource_HSE_Div2 RCC_PLLSource_HSI_Div1
    //  _RCC_PLLMul_x  为倍频因子*/
    while((RCC_GetFlagStatus(RCC_FLAG_PLLRDY))==RESET);
     /* Wait till PLL is ready */
    
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
     /* Select PLL as system clock source */
    //		SW[1:0]:系统时钟切换 (System clock switch)  位1:0
    //		由软件置’1’或清’0’来选择系统时钟源。
    //		在从停止或待机模式中返回时或直接或间接作为系统时钟的HSE出现故障时,由硬件强制选择
    //		HSI作为系统时钟(如果时钟安全系统已经启动)
    //		00:HSI作为系统时钟;
    //		01:HSE作为系统时钟;
    //		10:PLL输出作为系统时钟;
    //		11:不可用  */
    
    while (RCC_GetSYSCLKSource()!=0x08);  
  }else{
    
    
     
  }
}

/************************************************************
* @brief  
* void  fn_IRCC_SetSystic( uint32_t  _RCC_PLLMul_x );
* @param  
* @retval 
*************************************************************/ 
void  fn_IRCC_SetSystic( uint32_t  _RCC_PLLMul_x ){
    
    
  __IO uint32_t HSIStatus = 0;
  __IO uint32_t StartUpCounter = 0;
  /*SYSCLK  HCLK PCLK2 PCLK1 con figuration---*/
  RCC_DeInit();
  
  /*Enable HSE*/
  RCC_HSICmd(ENABLE);
  
  /* Wait till HSE is ready and if Time out is reached exit */
  do{
    
    
     HSIStatus = RCC->CR & RCC_CR_HSIRDY;
     StartUpCounter++;
  }while((HSIStatus == 0)&&(StartUpCounter != HSE_STARTUP_TIMEOUT));
  
  if(HSIStatus == SUCCESS){
    
    
     /*Enable Prefetch Buffer 预计缓冲区开启 */
     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
     /*FLASH 2 Wait state */ //这些位表示SYSCLK(系统时钟)周期与闪存访问时间的比例  
     FLASH_SetLatency(FLASH_Latency_2);
    // 这些位表示SYSCLK(系统时钟)周期与闪存访问的比例
    // SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
    // 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
    // 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
    // 0:0 < SYSCLK <= 24M
    // 1:24< SYSCLK <= 48M
    // 2:48< SYSCLK <= 72M */
    
      RCC_HCLKConfig(RCC_SYSCLK_Div1);
      /* HCLK = SYSCLK */     //AHB预分频 (AHB Prescaler) 
      RCC_PCLK1Config(RCC_HCLK_Div2);
      /* PCLK1 = HCLK */     //低速APB预分频(APB1) (APB low-speed prescaler (APB1))   
      RCC_PCLK2Config(RCC_HCLK_Div1);
      /* PCLK1 = HCLK */     //低速APB预分频(APB1) (APB low-speed prescaler (APB1))   
  
      RCC_PLLConfig(RCC_PLLSource_HSI_Div2,_RCC_PLLMul_x);
      RCC_PLLCmd(ENABLE);
      /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz 
      //  PLLSRC: PLL输入时钟源 (PLL entry clock source)
      //  RCC_PLLSource_HSE_Div1 RCC_PLLSource_HSE_Div2 RCC_PLLSource_HSI_Div1
      //  _RCC_PLLMul_x  为倍频因子*/
      
      while((RCC_GetFlagStatus(RCC_FLAG_PLLRDY))== RESET);
      /* Wait till PLL is ready */
      
      RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
      /* Select PLL as system clock source */
      
      //		SW[1:0]:系统时钟切换 (System clock switch)  位1:0
      //		由软件置’1’或清’0’来选择系统时钟源。
      //		在从停止或待机模式中返回时或直接或间接作为系统时钟的HSE出现故障时,由硬件强制选择
      //		HSI作为系统时钟(如果时钟安全系统已经启动)
      //		00:HSI作为系统时钟;
      //		01:HSE作为系统时钟;
      //		10:PLL输出作为系统时钟;
      //		11:不可用
          
      /** Wait till PLL is used as system clock source
            - 0x00: HSI used as system clock
            - 0x04: HSE used as system clock
            - 0x08: PLL used as system clock
      */
      while(RCC_GetSYSCLKSource()!=0x08);
  }else{
    
    
    
  }

}

/************************************************************
* @brief  
* void  fn_MCO_GPIO_Config(void);
* @param  
* @retval 
*************************************************************/ 
void  fn_MCO_GPIO_Config(void){
    
    
   GPIO_InitTypeDef  GPIO_InitStruct;
   GPIO_InitStruct.GPIO_Mode = RCC_OUT_GPIO_Modle;
   GPIO_InitStruct.GPIO_Pin = RCC_OUT_GPIO_Pin;
   GPIO_InitStruct.GPIO_Speed = RCC_OUT_GPIO_Speed;
   
   RCC_APB2PeriphClockCmd(RCC_OUT_GPIO_Clock,ENABLE);
   GPIO_Init(RCC_OUT_GPIO_Port,&GPIO_InitStruct);
   RCC_MCOConfig(RCC_MCO_SYSCLK);
   //RCC_MCOConfig(RCC_MCO_HSI);
   //RCC_MCOConfig(RCC_MCO_HSE);
}



4.利用之前的LED输出的 头文件 Led_book.h

代码如下(示例):

#ifndef  __LED_BOOK_H_
#define  __LED_BOOK_H_

#include "stm32f10x.h"

#define   LED_OUT_GPIO_Port     GPIOB                 //GPIO Point
#define   LED_OUT_GPIO_Clock    RCC_APB2Periph_GPIOB  //GPIO clock
#define   LED_OUT_GPIO_Pin      GPIO_Pin_5             
#define   LED_OUT_GPIO_Pin_Bit  5
#define   LED_OUT_GPIO_Modle    GPIO_Mode_Out_PP


typedef enum {
    
    
		LED_Corporate_On = 1,
		LED_Corporate_OFF = 2,
		LED_Corporate_Toggle = 3, 
} LED_Corporate_state_t;

void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,\
          uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef);

void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , \
          LED_Corporate_state_t _LED_Corporate_state_t );
  

#endif

2.利用之前的LED输出的 头文件 Led_book.c

代码如下(示例):

#include "Led_book.h"

#define LED_GPIO_Speed GPIO_Speed_10MHz 
void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef){
    
    
  GPIO_InitTypeDef  GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Mode = _GPIOMode_TypeDef;
  GPIO_InitStruct.GPIO_Pin = _GPIO_Pin_x;
  GPIO_InitStruct.GPIO_Speed = LED_GPIO_Speed;
  RCC_APB2PeriphClockCmd(_GPIO_Clock ,ENABLE);
  GPIO_Init(_GPIO_x , &GPIO_InitStruct) ; 
}

void fn_LED_Corporate(GPIO_TypeDef*  _GPIO_x , uint16_t  _GPIO_Pin_x , LED_Corporate_state_t  _LED_Corporate_state_t ){
    
    
  
  switch(_LED_Corporate_state_t){
    
    
    case  LED_Corporate_On :
      GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
      break;
		case  LED_Corporate_OFF:
      GPIO_ResetBits(_GPIO_x,_GPIO_Pin_x);
      break;
		case  LED_Corporate_Toggle:
      GPIO_ReadOutputDataBit(_GPIO_x,_GPIO_Pin_x)?GPIO_ResetBits(_GPIO_x,_GPIO_Pin_x):GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
      break;    
  }
}

//practice
//fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
// while(1){
    
    
//  delay(10000);
//  fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle);		 
// }	

3.建立RCC 输出的 主程序 main.c

代码如下(示例):

/**
  ******************************************************************************
  * @file    GPIO/JTAG_Remap/main.c 
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * 
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "PROJ_book.h" 

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
void delay(int x);

int main(void)
{
    
     
      fn_HRCC_SetSystic(RCC_PLLMul_2 );
 //   fn_IRCC_SetSystic(RCC_PLLMul_9 );
      fn_MCO_GPIO_Config();
      fn_Led_Init();
      while(1){
    
    
        delay(100000);
        fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle);
      }	   
}

void delay(int x){
    
    
	int y = 0xFFFFF;
	while((x--)>0){
    
    
		while((y--)>0){
    
    
			__NOP();
			__NOP();
			__NOP();
			__NOP();
			__NOP();
		}
	}
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

www.firebbs.cn。


参考笔记。
STM32 RCC – RCC 程序

STM32 RCC – LED 程序

STM32 RCC – 主程序

09 _STM32f103 时钟树 RCC


总结

 HSE时钟 
 HSE:High Speed External Clock signal,即高速的外部时钟。  
 来源:无源晶振(4-16M),通常使用8M。
 控制:RCC_CR 时钟控制寄存器的位16:HSEON控制

HSI时钟
 HSI:Low Speed Internal Clock signal,高速的内部时钟。
 来源:芯片内部,大小为8M,当HSE故障时,系统时钟会自动切换到HSI,直到HSE启动成功。
 控制: RCC_CR 时钟控制寄存器的位0:HSION控制

锁相环时钟
 锁相环时钟:PLLCLK 。
 来源:( HSI/2、HSE )经过倍频所得 。
 控制:CFGR:PLLXTPRE ,  PLLMUL。
 注意:PLL时钟源头使用HIS/2的时候,PLLMUL最大只能是16,这个时候PLLCLK最大只能是64M,小于ST官方推荐的最大时钟72M。

通过设置 PLL 的倍频因子,可以对PLL 的时钟来源进行倍频,倍频因子可以
是:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],具体设置成多少,由时钟配置寄存器 CFGR 的位
21-18:PLLMUL[3:0]设置。我们这里设置为 9倍频,因为上一步我们设置 PLL的时钟来源
为 HSE=8M,所以经过 PLL倍频之后的 PLL时钟:PLLCLK = 8M *9 = 72M。72M 是 ST
官方推荐的稳定运行时钟,如果你想超频的话,增大倍频因子即可,最高为 128M。我们
这里设置 PLL时钟:PLLCLK = 8M *9 = 72M。

系统时钟
 锁相环时钟:SYSCLK,最高为72M(ST官方推荐的)
 来源:HSI、HSE、PLLCLK。
 控制:CFGR:SW
 注意:通常的配置是SYSCLK=PLLCLK=72M。
系统时钟来源可以是:HSI、PLLCLK、HSE,具体的时钟配置寄存器 CFGR 的位 1-0:
SW[1:0]设置。我们这里设置系统时钟:SYSCLK = PLLCLK = 72M。

通过RCC_CFGR 寄存器 SWS 寄存器作为判定IC目前的时钟状态

HCLK时钟
 HCLK:AHB高速总线时钟,速度最高为72M。为AHB总线
的外设提供时钟、为Cortex系统定时器提供时钟
(SysTick)、为内核提供时钟(FCLK)。
 AHB:advanced high-performance bus。
 来源:系统时钟分频得到,一般设置HCLK=SYSCLK=72M
 控制: CFGR:HPRE

PCLK1时钟
 PCLK1:APB1低速总线时钟,最高为36M。为APB1总线
的外设提供时钟。2倍频之后则为APB1总线的定时器2-7提
供时钟,最大为72M。
 来源:HCLK分频得到,一般配置PCLK1=HCLK/2=36M
 控制: RCC_CFGR 时钟配置寄存器的PPRE1位

PCLK2时钟
 PCLK2:APB2高速总线时钟,最高为72M。为APB1总线
的外设提供时钟。为APB1总线的定时器1和8提供时钟,最
大为72M。
 来源:HCLK分频得到,一般配置PCLK1=HCLK=72M
 控制: RCC_CFGR 时钟配置寄存器的PPRE2位

RTC时钟   实时时钟
 RTC时钟:为芯片内部的RTC外设提供时钟。
 来源:HSE_RTC(HSE分频得到)、LSE(外部32.768KHZ的
晶体提供)、LSI(32KHZ)。
 控制: RCC备份域控制寄存器RCC_BDCR:RTCSEL位控制
独立看门狗时钟:IWDGCLK,由LSI提供

MCO时钟输出
 MCO:microcontroller clock output,微控制器时钟输出
引脚,由PA8复用所得。
 来源:PLLCLK/2,HSE、HSI、SYSCLK
 控制:CRGR:MCO

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

猜你喜欢

转载自blog.csdn.net/u012651389/article/details/117895309
今日推荐