前言
本文主要探讨STM32中比较重要的一个基础知识,RCC系统时钟,系统时钟也就是CPU的脉搏,决定CPU的速率,被誉为芯片的心跳,之后再文章中将会结合《STM32F10X-中文参考手册》进行介绍时钟树以及相关知识。
参考手册获取方式在上一篇博客中介绍
一、基础知识
(1)RCC – 复位和时钟控制器
RCC :reset clock control 复位和时钟控制器。 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。单片机有了时钟,才能够运行执行指令。
(2)HSE – 高速外部时钟信号
HSE: High Speed External Clock signal,高速外部时钟信号,HSE 是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从4-16MHZ 不等。当使用有源晶振时,时钟从OSC_IN 引脚进入,OSC_OUT 引脚悬空,当选用无源晶振时,时钟从OSC_IN 和OSC_OUT 进入,并且要配谐振电容。HSE 最常使用的就是8M 的无源晶振
(3)LSE – 低速外部时钟信号
LSE: Low Speed External Clock signal,低速外部时钟信号,即是OSC32_IN和OSC32_OUT接口。外部用于RTC的32.768KHz晶振
(4)HSI – 高速内部时钟信号
HSI: High Speed Internal Clock signal,高速内部时钟信号,出厂校准的8MHz内部RC振荡器。
(5)LSI – 高速内部时钟信号
LSI: Low Speed Internal Clock signal,高速内部时钟信号,带有校准功能的40KHz的内部RC振荡器。
(6)RTC – 实时时钟
RTC: Real Time Clock实时时钟,用于带有年、月、日、小时、分钟、秒钟的计时器。时间显示时候使用
(7)PLL – 锁相环
PLL:锁相环倍频输出,PLL 时钟来源可以有两个,一个来自HSE,另外一个是HSI/2,倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。HSI 是内部高速的时钟信号,频率为8M,根据温度和环境的情况频率会有漂移,一般不作为PLL 的时钟来源。这里我们选HSE 作为PLL 的时钟来源
(8)PLLCLK – PLL时钟
通过设置PLL 的倍频因子, 可以对PLL 的时钟来源进行倍频, 倍频因子可以是:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 具体设置成多少, 由时钟配置寄存器设置。例如:
设置PLL 的时钟来源为HSE=8M,PLL设置为9 倍频,所以经过PLL 倍频之后的PLL时钟:PLLCLK = 8M *9 = 72M。
72M 是ST 官方推荐的稳定运行时钟,如果你想超频的话,增大倍频因子即可,最高为128M。
(9)SYSCLK – 系统时钟
SYSCLK:系统时钟,系统时钟来源可以是:HSI、PLLCLK、HSE,具体的时钟配置寄存器设置。最高72MHz
(10)AHB – 高级高性能总线
AHB:高级高性能总线,这是一种“系统总线”AHB主要用于高性能模块(如CPU、DMA和DSP等)之间的连接。AHB 系统由主模块、从模块和基础结构(Infrastructure)3部分组成,整个AHB总线上的传输都由主模块发出,由从模块负责回应。
(11)APB
APB:是一种外围总线。APB主要用于低带宽的周边外设之间的连接,例如UART等,它的总线架构不像 AHB支持多个主模块,在APB里面唯一的主模块就是APB 桥。
(12)STM32 的多个时钟源
STM32本身十分复杂,外设非常多,但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费 。
而且同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树
(13)外部晶振与内部晶振的区别
外部晶振比较稳定而内部晶振的误差比较大,但如果对频率要求不高,如不涉及到串口通信和精确定时等情况时,则可以使用内部晶振。所以如果对频率要求不高,则一般是优先使用内部晶振。如果要省电,用到了SLEEP,则不能使用内部晶振,因为内部振荡会停止。
二、时钟树详解
首先简单介绍一下整个时钟树
在上图中标注了时钟树每一部分的组成,东西很多,看着也很乱,为了方便理解接下来选择其中的一条线进行介绍。
在上面这个图中,选取了一条时钟线,开始在(1)的位置 选择了外部高速时钟,一般选择8M,然后通过(2)的线路进入(3),在(3)也就是锁相环中,倍频选择x9,8M * 9 = 72M,经过前面的倍频,频率达到72M,也就是最大频率,之后进入APB预分频器(4)中,根据不同外设要求,根据不同外设需要挂载的总线,选择(5)或者(6),经过整个流程达到更改时钟频率的效果。小结一下:
系统时钟SYSCLK 的左边,系统时钟有很多种选择,也就是系统时钟可以从不同种类初始频率得到,就是设置系统时钟使用哪个时钟源;
系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率。
从左到右可以简单理解为 ,不同时钟源—>系统时钟来源的设置—>系统时钟—>AHB分频器—>各个外设分频倍频器 —> 外设时钟的设置
接下来分部分介绍:
系统时钟来源
由上图可知,系统时钟来源于三个部分:HSI 振荡器时钟、HSE 振荡器时钟、主 PLL (PLL) 时钟
初次之外还有两个次级时钟源
40 kHz 低速内部 RC (LSI RC),该 RC 用于驱动独立看门狗,也可选择提供给 RTC 用于停机/待机模式下的自动唤醒。
32.768 kHz 低速外部晶振(LSE 晶振),用于驱动 RTC 时钟 (RTCCLK)
USB时钟源
全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz
时钟输出
可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用。
时钟监视系统(CSS)
STM32还提供了一个时钟监视系统(CSS),用于监视高速外部时钟(HSE)的工作状态。倘若HSE失效,会自动切换(高速内部时钟)HSI作为系统时钟的输入,保证系统的正常运行。
AHB分频器给外设提供时钟
AHB分频器可选择1、2、4、8、16、64、128、256、512分频;
系统时钟经过AHB分频器分到五个部分:
(1)内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。
(2)Tick定时器:通过8分频后送给Cortex的系统定时器时钟。
(3)I2S总线:直接送给Cortex的空闲运行时钟FCLK(Free running Clock)。
(4)APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。
(5)APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。
另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
在 APB1(低速外设) 上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。即: APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM等设备。
在 APB2(高速外设) 上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。即 APB2负责AD,I/O,高级TIM,串口1等设备。对于不同芯片APB挂载的设备,可以在STM32相对于的芯片参考手册中查看
以上的时钟输出中,有很多是 带使能控制 的,例如AHB总线时钟、内核时钟、各种APB1外设、APB2外设等等。 当需要使用某模块时,一定要先使能对应的时钟。
系统时钟库函数
该函数截取自固件库文件system_stm32f103xe.c
为了方便阅读,我把英文注释翻译成了中文
该函数是直接操作寄存器的,有关寄存器部分请参考数据手册的RCC 的寄存器描述部分
void HSE_SetSysClock(void)
{
RCC_ClkInitTypeDef clkinitstruct = {0};
RCC_OscInitTypeDef oscinitstruct = {0};
/* Enable HSE Oscillator and activate PLL with HSE as source */
/* 使能HSE,并以HSE 作为PLL 时钟源*/
oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
oscinitstruct.HSEState = RCC_HSE_ON;
oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
oscinitstruct.PLL.PLLState = RCC_PLL_ON;
oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
{
/* Initialization Error */
/* 初始化错误*/
while (1);
}
/* Select PLL as system clock source and configure the HCLK, PCLK1
and PCLK2 clocks dividers */
/* 选择PLL 作为系统时钟源并配置HCLK,PCLK1 和PCLK2 分频系数*/
clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1
| RCC_CLOCKTYPE_PCLK2);
clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
{
/* Initialization Error */
/* 初始化错误*/
while (1);
}
}
void HSI_SetSysClock(void)
{
RCC_ClkInitTypeDef clkinitstruct = {0};
RCC_OscInitTypeDef oscinitstruct = {0};
/* Enable HSE Oscillator and activate PLL with HSE as source */
/* 使能HSI, 并以HSI 作为PLL 时钟源*/
oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
oscinitstruct.HSEState = RCC_HSE_ON;
oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
oscinitstruct.PLL.PLLState = RCC_PLL_ON;
oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
{
/* Initialization Error */
/* 初始化错误*/
while (1);
}
/* Select PLL as system clock source and configure the HCLK, PCLK1
and PCLK2 clocks dividers */
/* 选择PLL 作为系统时钟源并配置HCLK,PCLK1 和PCLK2 分频系数*/
clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1
| RCC_CLOCKTYPE_PCLK2);
clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
{
/* Initialization Error */
while (1);
}
}
总结
本文详细的介绍了STM32RCC时钟的相关知识,分析了整个时钟树,最后附上了相关的库函数。文章来源:https://www.toymoban.com/news/detail-509207.html
博客制作过程中难免有一些疏漏和不严谨之处,有问题欢迎评论区批评指正。文章来源地址https://www.toymoban.com/news/detail-509207.html
到了这里,关于STM32基础知识(三)-- 系统时钟RCC详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!