目录
一. STM32时钟树
1.这里主要熟悉SYSCLK的时钟流程即可. (主要是配置好锁相环)
二. 核心寄存器分析
1.RCC_CR时钟控制寄存器
- RCC_CR寄存器主要是控制时钟状态/使能标志位. 值得注意的是PLLON使能标志位, 后面配置锁相环部分需要先失能.
2.RCC_CFGR时钟配置寄存器
- RCC_CFGR寄存器主要是负责配置时钟树种, 各个线路上时钟源的选择以及倍频/分频系数.
3.其他寄存器
- RCC还有时钟中断寄存器, 复位/使能(APB1/APB2)寄存器, 备份区域控制和控制状态寄存器. 这些等后面接触到再做了解.
三. RCC外设驱动
1. 操作寄存器方式驱动
- 这里以官方的代码作为参考, 从这里可以看出官方将SYSCLK配置为72M, 并将主要的总线上的时钟频率也配置为官方推荐的最大值. 所以外后外设使用无特殊要求, 不需要修改时钟.
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
// ① 使能HSE,并等待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 预存取缓冲区 */
FLASH->ACR |= FLASH_ACR_PRFTBE;
// SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
// 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
// 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
//------------------------------------------------------------
// ② 设置AHB、APB2、APB1预分频因子
// HCLK = SYSCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//PCLK2 = HCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//PCLK1 = HCLK/2
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
// ③ 设置PLL时钟来源,设置PLL倍频因子,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);
// ④ 使能 PLL
RCC->CR |= RCC_CR_PLLON;
// ⑤ 等待PLL稳定
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
// ⑥ 选择PLL作为系统时钟来源
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启动失败,用户可以在这里添加错误代码出来
}
}
1. 固件库方式驱动
- 参考官方寄存器的驱动方式, 用固件库仿写一个可以传参修改SYSCLK时钟的函数. SYSCK要想修改最少要保障一下几点(如第一段代码所示), 详细规整代码如第二段所示.
第一段代码
#include "stm32f10x.h"
int main()
{
ErrorStatus state;
GPIO_InitTypeDef GPIO_InitStructures;
//要想修改SYSCLK的代码, 必须要重置RCC寄存器, 失能PLL然后设置PLL锁相环时钟源和参数. 最后使能PLL并设置PLLCLK为SYSCLK时钟
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);
RCC_PLLCmd(ENABLE);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructures.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructures.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructures.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructures);
RCC_MCOConfig(RCC_MCO_SYSCLK);
}
第二段规整版代码
void HSE_SetSysClock(uint32_t pllmul)
{
__IO uint32_t StartUpCounter = 0, HSEStartUpStatus = 0;
// 把RCC外设初始化成复位状态
RCC_DeInit();
//使能HSE,开启外部晶振,野火STM32F103系列开发板用的是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) {
}
}
}
四. RCC外设驱动总结
标签:CFGR,SYSCLK,详解,寄存器,RCC,uint32,时钟 From: https://www.cnblogs.com/Deng-S/p/17715526.html
- 无特殊需求, 直接使用使用配置好的时钟频率即可.如果需要修改部分外设, 例如APB1/APB2上面的外设时钟频率只需要调用固件库中的函数, 修改倍频/分频系数即可.(SYSCLK一般不做修改)