历史上的今天
今天是:2024年12月14日(星期六)
2021年12月14日 | STM32系统时钟RCC工作流程详解+配置函数中文注释+使用HSE代码
2021-12-14 来源:eefocus
前言
STM32系统时钟RCC工作流程详解
提示:以下是本篇文章正文内容
一、时钟树

二、工作流程
1.配置外部高速时钟HSE

HSE 是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从 4-16MHZ 不等。
HSE 最常使用的就是 8M 的无源晶振。当确定 PLL 时钟来源的时候,HSE 可以不分频或者 2 分频,这个由时钟配置寄存器 CFGR 的 位 17:PLLXTPRE 设置。
配置:设置为 HSE 不分频。
2.配置锁相环PLL时钟源

PLL时钟来源可以有两个,一个来自HSE,另外一个是 HSI/2,具体用哪个由时钟配置寄存器 CFGR 的位 16:PLLSRC 设置。
HSI 是内部高速的时钟信号,频率为 8M,根据温度和环境的情况频率会有漂移,一般不作为 PLL的时钟来源
配置:选 HSE作为 PLL的时钟来源。
3.配置锁相环PLL倍频因子得PLL 时钟 PLLCLK

通过设置 PLL 的倍频因子,可以对 PLL 的时钟来源进行倍频,倍频因子可以是:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],具体设置成多少,由时钟配置寄存器 CFGR 的位21-18:PLLMUL[3:0]设置。
配置:设置为 9 倍频
4.配置系统时钟 SYSCLK

系统时钟来源可以是:HSI、PLLCLK、HSE,具体的时钟配置寄存器 CFGR 的位 1-0:SW[1:0]设置。
配置:设置系统时钟:SYSCLK = PLLCLK = 72M。
5.配置AHB总线分频因子

系统时钟 SYSCLK 经过 AHB 预分频器分频之后得到时钟叫 APB 总线时钟,即 HCLK,分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器 CFGR的位 7-4 :HPRE[3:0]设置。片上大部分外设的时钟都是经过 HCLK 分频得到,至于 AHB总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好 APB 的时钟即可。
配置:里设置为 1 分频,即 HCLK=SYSCLK=72M。
6.配置APB1总线分频因子

APB1 总线时钟 PCLK1 由 HCLK 经过低速 APB 预分频器得到,分频因子可以是:[1,2,4,8,16],具体的由时钟配置寄存器 CFGR 的位 10-8:PRRE1[2:0]决定。HCLK1 属于低速的总线时钟,最高为 36M,片上低速的外设就挂载到这条总线上,比如USART2/3/4/5、SPI2/3,I2C1/2等。至于 APB1总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好 APB1 的时钟即可。
配置:设置为 2 分频,即 PCLK1 = HCLK/2 = 36M。
7.配置APB2总线分频因子

APB2总线时钟 PCLK2由 HCLK经过高速 APB2预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器 CFGR的位 13-11:PPRE2[2:0]决定。HCLK2属于高速的总线时钟,片上高速的外设就挂载到这条总线上,比如全部的 GPIO、USART1、SPI1 等。至于 APB2 总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好 APB2 的时钟即可。
配置:设置为 1 分频,即 PCLK2 = HCLK =72M。
三、时钟配置函数中文注释
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* 使能 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->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK = 72M */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK = 72M */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK = 36M*/
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
/* 锁相环配置: 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)
{
}
/* 选择PLLCLK作为系统时钟*/
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 启动失败,用户可以在这里添加处理错误的代码 */
}
}
四、使用HSE配置代码
HSE固件库配置.c
#include "bsp_rccclkconfig.h"
void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
{
ErrorStatus HSEStatus;
// 把RCC 寄存器复位成复位值
RCC_DeInit();
// 使能 HSE
RCC_HSEConfig(RCC_HSE_ON);
HSEStatus = RCC_WaitForHSEStartUp();
if( HSEStatus == SUCCESS )
{
// 使能预取指
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
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);
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
/* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
}
}
void HSI_SetSysClk( uint32_t RCC_PLLMul_x )
{
__IO uint32_t HSIStatus = 0;
// 把RCC 寄存器复位成复位值
RCC_DeInit();
// 使能 HSI
RCC_HSICmd(ENABLE);
HSIStatus = RCC->CR & RCC_CR_HSIRDY;
if( HSIStatus == RCC_CR_HSIRDY )
{
// 使能预取指
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
// 配置 PLLCLK = HSE * RCC_PLLMul_x
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
// 使能PLL
RCC_PLLCmd(ENABLE);
// 等待PLL稳定
while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
// 选择系统时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
/* 如果HSI 启动失败,用户可以在这里添加处理错误的代码 */
}
}
void MCO_GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
HSE固件库配置.h
#ifndef __BSP_RCCCLKCONFIG_H
#define __BSP_RCCCLKCONFIG_H
#include "stm32f10x.h"
void HSE_SetSysClk( uint32_t RCC_PLLMul_x );
void MCO_GPIO_Config();
void HSI_SetSysClk( uint32_t RCC_PLLMul_x );
#endif /*__BSP_RCCCLKCONFIG_H */
main.c
#include "stm32f10x.h" // 相当于51单片机中的 #include #include "bsp_led.h" #include "bsp_rccclkconfig.h" void Delay( uint32_t count ) { for(; count!=0; count--); } int main(void) { // 来到这里的时候,系统的时钟已经被配置成72M。 //HSE_SetSysClk( RCC_PLLMul_9 ); //HSI_SetSysClk( RCC_PLLMul_16 ); MCO_GPIO_Config(); RCC_MCOConfig(RCC_MCO_SYSCLK); //RCC_MCOConfig(RCC_MCO_HSI); LED_GPIO_Config(); while(1) { LED_G(OFF); Delay(0xFFFFF); LED_G(ON); Delay(0xFFFFF); } } 五、收获 1.系统时钟的配置逻辑 配置外部高速时钟HSE 配置锁相环PLL时钟源 配置锁相环PLL倍频因子得PLL 时钟 PLLCLK 配置系统时钟 SYSCLK 配置AHB总线分频因子 配置APB1总线分频因子 配置APB2总线分频因子 2. CSS时钟安全系统的作用 当外部HSE时钟发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和TiM8)的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。此CSSI中断连接到NMI中断(不可屏蔽中断)。 如果HSE时钟发生故障,可以选择HSI时钟,配置8M经过二分频变为4M。时钟安全系统最重要的作用是提醒用户时钟故障,因尽快保存数据。 
下一篇:STM32启动文件执行步骤分析
史海拾趣
|
用Atmega8单片机自制智能型液晶显示充电器 (527DZ作品) 一、概述: 移动通讯、消费类数码产品、笔记本电脑、便携仪器等便携设备市场的不断扩张,使得我们对电池的性能和工作寿命的要求不断地提高。从20世纪60年代的商用镍镉和密封铅酸电池到近几年的镍氢和锂离子技术,可充电电池容量和性能得到 ...… 查看全部问答> |
|
将一个变量说明为volatile表示这个变量是“易变的”。如果一个变量会被其它引用改变,或在其它并行的任务中会被改变(例如中断服务程序),都要显式地说明为“volatile”,否则在编译器优化阶段会作出错误的判断,例如将这个变量读入寄存器以后,在 ...… 查看全部问答> |
|
安装evc4.0的问题(愁的头发白了,高手一定帮帮忙啊!!) 我在最近学习wince,因为周围就我一人在搞,导师还在催,天天郁闷 现在装evc4.0时,按照网上给的步骤装的: 1、安装ACTIVE SYNC(MSASYNC.EXE) 2、安装EVC4.0 3、安装evc4sp2.exe 4、安装Mic ...… 查看全部问答> |
|
#include<stdio.h>#include<reg51.h>//实例12:用自增运算控制P0口8位LED流水花样#include<reg51.h> //包含单片机寄存器的头文件/******************************************************函数功能:延时一段时间************** ...… 查看全部问答> |
|
1、P2口接8个LED灯,实现花样流水灯表演。 2、P0口接一位共阳数码管(例如:0901051101),重复显示。或者每隔一秒钟时间,显示下一位数字。例如:先显示数字0;隔一秒钟时间,显示数字9,再隔一秒钟,显示数字0。 3、P1.6接继电器(常开触点一个 ...… 查看全部问答> |




