RCC :reset clock control 复位和时钟控制器
这里只需要理解时钟部分。
RCC主要作用
设置系统时钟 SYSCLK、设置 AHB 分频因子(决定 HCLK 等于多少)、设置 APB2 分频因子(决定 PCLK2 等于多少)、设置 APB1 分频因子(决定 PCLK1 等于多少)、设置各个外设的分频因子;控制 AHB、APB2 和 APB1 这三条总线时钟的开启、控制每个外设的时钟的开启。对于 SYSCLK、HCLK、PCLK2、PCLK1 这四个时钟的配置一般是:PCLK2 = HCLK = SYSCLK=PLLCLK = 72M,PCLK1=HCLK/2 = 36M。
系统时钟
根据时钟树的黄色部分来分析系统时钟的设置路径。
1.HSE:高速外部时钟信号
由有源晶振和无源晶振提供。有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空,当选用无源晶振时,时钟从OSC_IN和OSC_OUT进入,并且要配谐振电容。
HSE 最常使用的就是 8M 的无源晶振。当确定 PLL 时钟来源的时候,HSE 可以不分频或者 2 分频,这个由时钟配置寄存器 CFGR 的位 17:PLLXTPRE 设置,我们设置为 HSE 不分频。
2.PLL时钟源
一个来自HSE,另一个来自HSI/2,由时钟配置寄存器CFGR 的位 16:PLLSRC 设置。HSI是内部高速的时钟信号,频率为8M(收环境和温度影响,频率会发生漂移,不用作PLL时钟来源)。
3.PLL时钟PLLCLK
设置PLLMUL倍率因子,可对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 官方推荐的稳定运行时钟,如果你想超频的话,增大倍频因子即可。
4.系统时钟SYSCLK
系统时钟来源可以是:HSI、PLLCLK、HSE。的时钟配置寄存器 CFGR 的位 1-0:SW[1:0] 设置。我们这里设置系统时钟:SYSCLK = PLLCLK = 72M。
5.AHB总线时钟HCLK
系统时钟 SYSCLK 经过 AHB 预分频器分频之后得到时钟叫 APB 总线时钟,即 HCLK,分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器 CFGR 的位 7-4 :HPRE[3:0]设置。设置为 1 分频,即 HCLK=SYSCLK=72M。
6.APB2 总线时钟 PCLK2
APB2 总线时钟 PCLK2 由 HCLK 经过高速 APB2 预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器 CFGR 的位 13-11:PPRE2[2:0] 决定。HCLK2 属于高速的总线时钟,片上高速的外设就挂载到这条总线上,比如全部的 GPIO、USART1、SPI1 等。设置为 1 分频,即 PCLK2 = HCLK = 72M。
7.APB1 总线时钟 PCLK1
APB1 总线时钟 PCLK1 由 HCLK 经过低速 APB 预分频器得到,分频因子可以是:[1,2,4,8,16],具体的由时钟配置寄存器 CFGR 的位 10-8:PRRE1[2:0] 决定。
采用HSE作为外部时钟源时,编写RCC时钟的驱动文件,bsp_clkconfig.h 和 bsp_clkconfig.c。
编程要点对应着时钟树图中的序号。
1、开启 HSE/HSI ,并等待 HSE/HSI 稳定
2、设置 AHB、APB2、APB1 的预分频因子
3、设置 PLL 的时钟来源,和 PLL 的倍频因子,设置各种频率主要就是在这里设置
4、开启 PLL,并等待 PLL 稳定
5、把 PLLCK 切换为系统时钟 SYSCLK
6、读取时钟切换状态位,确保 PLLCLK 被选为系统时钟
bsp_clkconfig.c
#include "bsp_rccclkconfig.h"
void HSE_SetSysClk(uint32_t RCC_PLLMul_x) //创建固件库函数,使用高速外部时钟HSE来设置系统时钟
{
ErrorStatus HSEStatus;
//把RCC寄存器复位成复位值
RCC_DeInit();
//使能HSE
RCC_HSEConfig(RCC_HSE_ON);
/* 等待HSE就绪并做超时处理 */
HSEStatus = RCC_WaitForHSEStartUp();
if(HSEStatus == SUCCESS)
{
//使能预取指,开启缓存区
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//缓存区2个延时周期
FLASH_SetLatency(FLASH_Latency_2);
//设置 HCLK=72M PCLK1=36M PCLK2=72M 倍率因子
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
//锁相环配置: PLLCLK = HSE * RCC_PLLMul_x
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
//使能PLL
RCC_PLLCmd(ENABLE);
//等待PLL稳定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
//选择系统时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//判断PLL是否为时钟源
while(RCC_GetSYSCLKSource() != 0x08);
}
else
{
/* 如果HSE启动失败,用户可以在这里添加处理错误的代码 */
}
}
MCO输出
MCO微控制器时钟输出,在 STM32 F1 系列中由PA8 复用所得,主要作用是可以对外提供时钟,相当于一个有源晶振。MCO 的时钟来源可以是:
PLLCLK/2、HSI、HSE、SYSCLK,具体选哪个由时钟配置寄存器 CFGR 的位 26-24:MCO[2:0] 决定。
bsp_clkconfig.c
void MCO_GPIO_Config() //MCO主时钟输出函数
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //启用AP2外部时钟
//配置GPIO_InitTypeDef初始化类型
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //GPIOA8引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct); //将配置好的结构体成员配置到相应的寄存器里
}
bsp_clkconfig.h
#ifndef __BSP_RCCCLKCONFIG_H_
#define __BSP_RCCCLKCONFIG_H_
#include "stm32f10x.h"
void HSE_SetSysClk(uint32_t RCC_PLLMul_x);
void MCO_GPIO_Config();
#endif
main()
#include "stm32f10x.h" //相当于51单片中的#include <reg51.h>
#include "bsp_led.h"
#include "bsp_rccclkconfig.h"
void delay(unsigned int i) //延时函数
{
while(i--);
}
int main(void)
{
//来到这里的时候,系统时钟已经被配置好72M.
HSE_SetSysClk(RCC_PLLMul_9); //超时频率配置
MCO_GPIO_Config(); //MCO主时钟输出函数,PA8
RCC_MCOConfig(RCC_MCO_SYSCLK); //选择SYSCLK时钟源输出
LED_GPIO_Config();
while(1)
{
//GPIO_SetBits(LED_G_GPIO_PORT, LED_G_GPIO_PIN);
LED_G(OFF);
delay(0xFFFFF);
//GPIO_ResetBits(LED_G_GPIO_PORT, LED_G_GPIO_PIN);
LED_G(ON);
delay(0xFFFFF);
}
}
初学者stm32,有何错误,欢迎指出改正!!!