9.1 RCC的工作原理

在讲解RCC之前,我们现回顾一下时钟树。在《详解STM32时钟系统》一章中,我们详细讲解了STM32的系统时钟,在这里就当总结前文的内容,不再一一讲解。

​详解STM32时钟系统​

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_寄存器


图1时钟树

9.2 RCC的寄存器描述

RCC的相关寄存器比较多,下面进行一一介绍。

 时钟控制寄存器(RCC_CR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_STM32_02

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_寄存器_03


图2 时钟控制寄存器(RCC_CR)

 时钟配置寄存器(RCC_CFGR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_STM32_04

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_寄存器_05


图3时钟配置寄存器(RCC_CFGR)

 时钟中断寄存器 (RCC_CIR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_STM32_06

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_系统时钟_07

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_寄存器_08


图4时钟中断寄存器 (RCC_CIR)

 APB2 外设复位寄存器 (RCC_APB2RSTR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_STM32_09

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_RCC_10


图5 APB2 外设复位寄存器 (RCC_APB2RSTR)

 APB1 外设复位寄存器 (RCC_APB1RSTR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_系统时钟_11

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_晶振_12

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_STM32_13


图6 APB1 外设复位寄存器 (RCC_APB1RSTR)

 AHB外设时钟使能寄存器 (RCC_AHBENR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_晶振_14

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_系统时钟_15


图7 AHB外设时钟使能寄存器 (RCC_AHBENR)

 APB2 外设时钟使能寄存器(RCC_APB2ENR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_寄存器_16

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_系统时钟_17


图8 APB2 外设时钟使能寄存器(RCC_APB2ENR)

 APB1 外设时钟使能寄存器(RCC_APB1ENR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_RCC_18

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_系统时钟_19

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_RCC_20


图9 APB1 外设时钟使能寄存器(RCC_APB1ENR)

 备份域控制寄存器 (RCC_BDCR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_RCC_21


图10备份域控制寄存器 (RCC_BDCR)

 控制/状态寄存器 (RCC_CSR)

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_STM32_22

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_系统时钟_23


图11控制/状态寄存器 (RCC_CSR)

9.3 RCC的具体代码分析

在具体分析代码之前,首先给出库函数的相关实现函数。

 时钟频率

typedef struct
{
uint32_t SYSCLK_Frequency; /*!< 系统时钟频率,单位:Hz */
uint32_t HCLK_Frequency; /*!< AHB总线时钟频率,单位:Hz */
uint32_t PCLK1_Frequency; /*!< APB1总线时钟频率,单位:Hz */
uint32_t PCLK2_Frequency; /*!< APB2总线时钟频率,单位:Hz */
uint32_t ADCCLK_Frequency; /*!< ADC模块输入时钟频率,单位:Hz */
}RCC_ClocksTypeDef;

 RCC库函数

RCC库函数原型及实现请详见stm32f10x_rcc模块,以下仅介绍各接口的作用。

RCC_DeInit 将外设RCC寄存器重设为缺省值

RCC_HSEConfig 设置外部高速晶振( HSE)

RCC_WaitForHSEStartUp 等待 HSE 起振

RCC_AdjustHSICalibrationValue 调整内部高速晶振( HSI)校准值

RCC_HSICmd 使能或者失能内部高速晶振( HSI)

RCC_PLLConfig 设置 PLL 时钟源及倍频系数

RCC_PLLCmd 使能或者失能

PLLRCC_SYSCLKConfig 设置系统时钟( SYSCLK)

RCC_GetSYSCLKSource 返回用作系统时钟的时钟源

RCC_HCLKConfig 设置 AHB 时钟( HCLK)

RCC_PCLK1Config 设置低速 AHB 时钟( PCLK1)

RCC_PCLK2Config 设置高速 AHB 时钟( PCLK2)

RCC_ITConfig 使能或者失能指定的 RCC 中断

RCC_USBCLKConfig 设置 USB 时钟( USBCLK)

RCC_ADCCLKConfig 设置 ADC 时钟( ADCCLK)

RCC_LSEConfig 设置外部低速晶振( LSE)

RCC_LSICmd 使能或者失能内部低速晶振( LSI)

RCC_RTCCLKConfig 设置 RTC 时钟( RTCCLK)

RCC_RTCCLKCmd 使能或者失能 RTC 时钟

RCC_GetClocksFreq 返回不同片上时钟的频率

RCC_AHBPeriphClockCmd 使能或者失能 AHB 外设时钟

RCC_APB2PeriphClockCmd 使能或者失能 APB2 外设时钟

RCC_APB1PeriphClockCmd 使能或者失能 APB1 外设时钟

RCC_APB2PeriphResetCmd 强制或者释放高速 APB( APB2)外设复位

RCC_APB1PeriphResetCmd 强制或者释放低速 APB( APB1)外设复位

RCC_BackupResetCmd 强制或者释放后备域复位

RCC_ClockSecuritySystemCmd 使能或者失能时钟安全系统

RCC_MCOConfig 选择在 MCO 管脚上输出的时钟源

RCC_GetFlagStatus 检查指定的 RCC 标志位设置与否

RCC_ClearFlag 清除 RCC 的复位标志位

RCC_GetITStatus 检查指定的 RCC 中断发生与否

RCC_ClearITPendingBit 清除 RCC 的中断待处理位

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_RCC_24

接下来,笔者再这里给出HSE的配置步骤。

 RCC配置步骤

1、将RCC寄存器恢复为默认值 RCC_DeInit

2、打开外部高速时钟晶振 RCC_HSEConfig

3、等待外部高速时钟晶振工作 RCC_WaitForHSEStartUp

4、设置AHB时钟 RCC_HCLKConfig

5、设置高速APB时钟 RCC_PCLK2Config

6、设置低速APB时钟 RCC_PCLK1Config

7、设置PLL锁相环 RCC_PLLConfig

8、打开PLL锁相环 RCC_PLLCmd

9、等待PLL锁相环工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)

10、设置系统时钟 RCC_SYSCLKConfig

11、判断PLL是否为系统时钟 while(RCC_GetSYSCLKSource()!=0x08)

12、打开要使用的外设时钟 RCC_APB2PeriphClockCmd/RCC_APB1PeriphClockCmd

以上步骤只是针对HSE的配置总结了配置步骤,对于RCC的更多配置请查阅参考手册与库函数的手使用册。

具体的HSE配置代码如下。

void HSE_SetSysClock(uint32_t pllmul)
{
__IO uint32_t StartUpCounter = 0, HSEStartUpStatus = 0;

// 把RCC外设初始化成复位状态
RCC_DeInit();

//使能HSE,开启外部晶振,秉火开发板用的是8M
RCC_HSEConfig(RCC_HSE_ON);

// 等待 HSE 启动稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp();

// 只有 HSE 稳定之后则继续往下执行
if (HSEStartUpStatus == SUCCESS)
{
//----------------------------------------------------------------------//
// 这两句是操作FLASH闪存用到的,如果不操作FLASH的话,这两个注释掉也没影响
// 使能FLASH 预存取缓冲区
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

// SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
// 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
// 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M
FLASH_SetLatency(FLASH_Latency_2);
//----------------------------------------------------------------------//

// AHB预分频因子设置为1分频,HCLK = SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);

// APB2预分频因子设置为1分频,PCLK2 = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);

// APB1预分频因子设置为1分频,PCLK1 = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);

//-----------------设置各种频率主要就是在这里设置-------------------//
// 设置PLL时钟来源为HSE,设置PLL倍频因子
// PLLCLK = 8MHz * pllmul
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);
//------------------------------------------------------------------//

// 开启PLL
RCC_PLLCmd(ENABLE);

// 等待 PLL稳定
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}

// 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

// 读取时钟切换状态位,确保PLLCLK被选为系统时钟
while (RCC_GetSYSCLKSource() != 0x08)
{
}
}
else
{ // 如果HSE开启失败,那么程序就会来到这里,用户可在这里添加出错的代码处理
// 当HSE开启失败或者故障的时候,单片机会自动把HSI设置为系统时钟,HSI是内部的高速时钟,8MHZ
while (1)
{
}
}
}

9.4实验现象

将程序编译好后下载到板子上,可以看到LED1不停闪烁。





代码获取方法

1.长按下面二维码,关注公众号[嵌入式实验楼]

2.在公众号回复关键词[STM32F1]获取资料

《嵌入式-STM32开发指南》第二部分 基础篇 - 第9章RCC_寄存器_25




欢迎访问我的网站:

​BruceOu的哔哩哔哩​

​BruceOu的主页​

​BruceOu的博客​

 ​​BruceOu的简书​