本文展示了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 程序
总结
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