STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)

关于 RCC 配置系统时钟和外部输出 MCO

这张图 STM32F103 时钟树原理图,接下来我会在这张图里一小段一小段截取来分开讲解。

STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第1张图片

HSE 和 HSI 系统时钟输出

PLL 时钟源可以来源于两个,一个是 HSE ,另一个是 HSI 。
HSE 是如何作为时钟源呢?
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第2张图片

1、这个是 HSE 高速外部时钟1的输入, 可以很清楚的看到外部接了 OUT 和 IN 两个引脚,外部有源或者无源晶振通过这两个引脚提供时钟信号(当是有源晶振时,时钟从 IN 进入, OUT 悬空, 当是无源晶振时,时钟从 IN 和 OUT 进入,并且要配谐振电容。)。
2、当确定 PLL 时钟来源时,可以选择不分频或者 2 分频,这个可以由 RCC 的 CFGR 寄存器的 PLLXTPRE 配置。

STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第3张图片
在这里插入图片描述
HSI 又是怎么作为时钟源呢?
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第4张图片
HSI 是内部高速时钟信号,只能 2 分频来作为 PLL 时钟源,但是根据温度和环境情况频率会有漂移,所以一般不作为 PLL 时钟源。

STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第5张图片
1、通过上面所讲的配置 HSE 和 HSI 两个时钟作为 PLL 时钟的来源,可以通过 CFGR (寄存器上面已经讲到)的 PLLSRC 来配置来源。

STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第6张图片
/2、一般来说常用 8 M 频率,所以接下来就用 HSE 和 HSI 为 8M 来作为例子,在
这儿可以对时钟来源进行倍频,可以通过 CFGR 的 PLLMUL 来配置。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第7张图片
因为我们使用的是 8M 时钟,所以这儿经过倍频了之后最高可以达到 8M * 16 = 128M 的频率,但是官方推荐的是 72M 稳定时钟。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第8张图片
这儿我们可以看到,系统时钟的来源一共有 3 个,除了我们上述配置的 PLL 时钟,还可以直接使用 HSE 和 HSI 直接作为时钟来源,可以通过 CFGR 的 SW 来配置。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第9张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第10张图片
这儿可以看到,系统时钟会经过 AHB 预分频器,得到的叫做 APB 总线时钟(即 HCLK )。

STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第11张图片
我们可以通过设置 CFGR 的 HPRE 来设置分频器,大部分外设的时钟都是通过这个 HCLK 分频的得到,至于 AHB 总线上的时钟为多少,得等到我们使用该外设时才能用到,所以我们这儿只需要粗线条的配置 APB 的时钟就可以了。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第12张图片
这要注意,如果 AHB 的预分频器大于2,必须开启预缓冲器,我在闪存取读中并没有找到(不代表没有,只是博主没有看到,因为博主英文差,所以读英文版有些困难,如果有哪位大佬找到愿意分享,博主还望大佬不吝赐教,谢谢!(后面我会讲解用固件库开启这个。))
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第13张图片

我们常用的 APB2 总线时钟(即 HCLK2 )经过高速到 APB2 预分频器获得,配置可以用 CFGR 的 PPRE2 。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第14张图片
HCLK2 是属于高速的总线时钟,高速的外设就挂载到这条总线上。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第15张图片
APB1 总线时钟(即 PCLK1 )经过低速到 APB 预分频器获得,配置可以用 CFGR 的 PPRE1 。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第16张图片
属于低速,最高只能达到 36M 低速外设就挂载在这个总线上。

以上就是关于 HSE 和 HSI 时钟的全部配置理论过程,接下来我会使用 STM32 的固件库来配置上面,配置原理与上面相同,理论是不是很枯燥,但是坚持一定很美丽,现在直接上代码讲解

1、以 HSE 作为时钟来源,经过PLL倍频来作为系统时钟。

//以HSE作为时钟来源,经过PLL倍频来作为系统时钟,这个是比较常用的。
void HSE_SetSysClock(uint32_t pllmul)	//定义一个函数,来代表这一个过程。
{
	__IO uint32_t HSEStartUpStatus = 0;	//__IO指的是静态变量,原型为volatile,代表允许除了程序员之外(比如硬件)来修改它的内容。
	
	RCC_DeInit();	//在stm32f10x_rcc.h里,是外设时钟初始化。
	RCC_HSEConfig();	//使能HSE,开启外部晶振,我的开发板使用的是8M。
	HSEStartUpStatus = RCC_WaitForHSEStartUp();	//等待HSE稳定,若是稳定了会返回SUCCES这个值。
	if (HSEStartUpStatus = SUCCESS)	//判断是否成功启动并且稳定。
	{
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);	//使能FLASH缓冲区。
//SYSCLK周期与闪存访问时间的比例设置,设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了。
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M
		FLASH_SetLatency(FLASH_Latency_2);
		RCC_HCLKConfig(RCC_SYSCLK_Div1);	//AHB预分频因子设置为1分频。
		RCC_PCLK2Config(RCC_HCLK_Div1);	//APB2预分频因子设置为1分频。
		RCC_PCLK1Config(RCC_HCLK_Div2);	//APB1预分频因子设置为1分频。
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);	//设置时钟来源为HSE,倍频为8M*pllmul。
		RCC_PLLCmd(ENABLE);	//开启PLL。
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);	//等待PLL稳定,代码中相关寄存器作用会在HSE和HSI讲解完后详细讲解。
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);	//把PLL时钟切换成系统时钟。
		while (RCC_GetSYSCLKSource() != 0x08);	//读取时钟切换状态,确保PLLCLK被选为系统时钟。
	}
	else
	{
		//这儿是HSE开启失败,程序就会来这儿,博主是只做了一个死循环处理(因为博主只是学习阶段,并不是做项目阶段,所以并没有太在意这儿,但是个别情况下还是添加一下失败处理,例如重启/复位什么的。)
		while (1);
	}
}
//至此,HSE就配置好了。我们只需要调用HSE_SetSysClock函数就可以了。
//例如:
	HSE_SetSysClock(13);	//代表8*13=104M的频率,调整参数可以改变。

HSI 的配置与上面大同小异,所以我只在不同的地方设置。

void HSI_SetSysClock(uint32_t pllmul)
{
	__IO uint32_t HSIStartUpStatus = 0;

	RCC_DeInit();
	RCC_HSICmd(ENABLE);
	HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;	//等待HSI,上面使用的是函数,这儿直接使用的是寄存器,本质一样。
	if (HSIStartUpStatus  == RCC_CR_HSIRDY)	//因为使用的寄存器,所以值就不是RESET,RESET是函数的返回值。
	{
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
		FLASH_SetLatency(FLASH_Latency_2);
		RCC_HCLKConfig(RCC_SYSCLK_Div1); 
		RCC_PCLK2Config(RCC_HCLK_Div1); 
		RCC_PCLK1Config(RCC_HCLK_Div2);
		RCC_PLLConfig(RCC_PLLSource_HSI_Div2, pllmul);	//设置时钟来源为HSI。
		RCC_PLLCmd(ENABLE);
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		while (RCC_GetSYSCLKSource() != 0x08);
	}
	else
	{
		while (1);
	}
}

在这儿, HSE 和 HSI系统时钟配置就弄好了。

接下来,我们来看看关于 RCC 的寄存器的作用吧。

CR 寄存器,时钟控制寄存器。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第17张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第18张图片
CFGR 寄存器,时钟配置寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第19张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第20张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第21张图片
CIR 寄存器,时钟中断寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第22张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第23张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第24张图片
APB2RSTR 寄存器, APB2 外设复位寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第25张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第26张图片
在这里插入图片描述
APB1RSTR 寄存器, APB1 外设复位寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第27张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第28张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第29张图片
AHBEND 寄存器, AHB 外设使能寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第30张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第31张图片
APB2END 寄存器, APB2 外设使能寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第32张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第33张图片
APB1END 寄存器, APB1 外设使能寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第34张图片STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第35张图片
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第36张图片
BDCR 寄存器,备份域控制寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第37张图片
CSR 寄存器,控制 / 状态寄存器
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第38张图片

在这里插入图片描述
以上,就是全部关于 RCC 的寄存器了。

接下来,就是关于 MCO 的讲解以及代码讲解。

MCO

什么是 MCO ?
为什么要配置 MCO ?

首先, MCO 是什么? MCO 就是由 STM32 内部向外部发出时钟信号。
为什么要配置 MCO ?这是因为在使用其他芯片的时候可能需要一个晶振来提供一个时钟信号,如果使用 MCO 来输出时钟信号,就可以在成本上减少一个晶振的使用。
其实 MCO 的配置也是使用 CFGR 的 MCO 配置,可以通过示波器检测是否配置正确。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第39张图片
这儿就可以很清楚的看到 MOC 的输出源。
STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第40张图片
这儿就可以配置输出源。

下面放代码实例:

//其实要把MCO作为外部输出只需要调用stm32f10x_rcc.h这个库函数就可以了。
	RCC_MCOConfig(RCC_MCO_SYSCLK);
//配置的参数可以参考下图。

STM32F103 关于 RCC 使用 HSE 和 HSI 配置系统时钟输出和 MCO 输出时钟信号(固件库详解)_第41张图片
到此为止,关于系统时钟配置和外部输出时钟已经弄好了,谢谢大家耐心观看,觉得博主写的不错的点赞关注一下再走吧,嘻嘻~

你可能感兴趣的:(STM32理论分析,stm32,单片机,经验分享)