
【STM32】系统时钟RCC详解(超详细,超全面) 1什么是时钟时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。 为什么 STM32 要有多个时钟源呢?' O4 U7 _8 h: G8 q ! r& Y! w$ V4 H 6 L" H: d5 {4 s STM32本身十分复杂,外设非常多 但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费 并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树1 `6 e% C# }3 I/ c+ m - e7 m/ T0 j- H9 a! j; y8 ? 总括:+ f6 o+ _; c5 n! d& B2 O- N STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。 系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)0 y' i7 X# t3 \) | 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。- U( i) x4 |) ~# R1 k) O, Y5 E- y 一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。 不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。 对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗, V0 ?- g( R+ K) T5 n: q3 G STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。 这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因 ) C/ H. ~$ A* g; I STM32的时钟系统框图 ![]() 7 I1 E* U; S, N% h6 T* H & o$ a% |+ }( J+ h% H 系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率9 x q4 K% W& n d" @5 J4 a/ c$ b 从左到右可以简单理解为 各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置 2 C) x# z1 l! N6 `* |6 U( ^ 时钟系统7 _7 U! m2 ~8 e1 B 1各个时钟源 (左边的部分)6 q0 v* w* V0 r8 [$ c2 j. \ STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。- _# y$ W4 c* |# L: N, i/ N ①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。' @1 B0 W- K7 T. T" M2 B ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。7 }+ [9 u5 j6 o; { ③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。7 y& @$ x4 N' V' d6 _9 n : E- ~* S F7 @- G 其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源 而独立使用 2 m+ i- S5 j2 m8 z% o2 R, ` # Y a- S2 t2 H( L8 ]* X # r3 \/ d# l, }1 ]* S- A! `1 m 而HSI高速内部时钟 HSE高速外部时钟 PLL锁相环时钟 这三个经过分频或者倍频 作为系统时钟来使用 ~0 |& h. I6 a7 d$ q! |! ] PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。 通过倍频之后作为系统时钟的时钟源 0 N! E, C7 e1 p, L 举个例子:Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。 或者内部RC振荡器(HSI) 为8MHz /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz , q" V/ m' u% ~" _4 c$ i. W$ m PS: 网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟 2系统时钟SYSCLK7 v! B* ]! u l; c 系统时钟SYSCLK可来源于三个时钟源:0 E7 m' u. E9 _: \: u ①、HSI振荡器时钟 ②、HSE振荡器时钟" t! M3 v! t; t ③、PLL时钟 最大为72Mhz ![]() ![]() 4把时钟信号输出到外部 ![]() 1 D! N7 Q( I# T R8 p ! R1 Y9 f* z8 ?5 u' z 5系统时钟通过AHB分频器给外设提供时钟(右边的部分) 重点 从左到右可以简单理解为 系统时钟--->AHB分频器--->各个外设分频倍频器 ---> 外设时钟的设置9 S8 H) s' i1 h0 e$ \ 右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用: 3 Y% B& T- P+ P% B; i4 G9 w3 f + j6 Y0 {& I; ?+ u C ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。 9 R! D h+ i3 u8 t, z3 v n$ F0 \! C# U ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。 ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。 / G7 Y+ ^, _# G9 c' ]0 j' R, q0 S ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。 8 ~: i& p- D, e7 N9 }7 J1 u0 ]6 w ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。 6 Z) r% l1 E+ @! J5 B# U 另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。 % _) \6 |& Z9 G+ H; I/ T6 k2 l5 m m9 W9 @9 N) N 需要注意的是,如果 APB 预分频器分频系数是 1,则定时器时钟频率 (TIMxCLK) 为 PCLKx。否则,定 时器时钟频率将为 APB 域的频率的两倍:TIMxCLK = 2xPCLKx。 4 v% [6 R, r3 A7 B: a3 E B APB1和APB2的对应外设 F1系列3 `7 {' w$ I, d ![]() * }' v5 H, o5 Z, B9 `% `3 [ $ A1 B. D: ]% c! Q+ L0 v2 } 而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。+ ~% F! W8 x9 R! C- W ! n# T& R, k' ?- Q0 | F4系列 ![]() : Q' o7 A* P# w+ h APB2总线:高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11 UTART1,USART6 APB1总线:通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7 UTART2~UTART5+ w/ L" i5 {+ h4 A5 U7 S( r2 ]+ t , q1 F8 n% { T9 i & U" D9 ~5 C Z% {4 G2 ^ F4系列的系统时钟频率最高能到168M+ t! P3 r, p2 w- y5 H& {, y / z3 B& L) T& K; M9 \+ ]- W 0 l! u2 y3 i4 }2 k 具体 可以在 stm32f10x_rcc.h 和stm32f40x_rcc.h 中查看 $ D; e! K& B- C2 q3 E5 w y6 r, O 或者通过 STM32参考手册搜索“系统架构”或者“系统结构” 查看外设挂在哪个时钟下,7 H1 [: K7 p$ H* f2 |( @- X3 T 6 n9 p7 ~/ B; L* j3 o5 E6 u5 Z ( x, U$ c' `2 w: } RCC相关寄存器:: I5 b& J% I$ S, r7 {; b5 U* H7 { 这里我们以F1系列为例0 L8 ]! W# l" {7 R- {' y7 h+ j
可以对上上面的时钟框图和RCC寄存器来学习,对STM32的时钟系统有个大概的了解 其实也就是我们上面介绍的流程,理解了自然也就能写出来 4 @9 u" k: y4 h, [ . T. e' \6 [* x: [" y RCC初始化: 这里我们使用HSE(外部时钟),正常使用的时候也都是使用外部时钟2 I K/ c# \4 o0 P6 D 使用HSE时钟,程序设置时钟参数流程: 1、将RCC寄存器重新设置为默认值 RCC_DeInit;- Y2 k/ s, W- k; Z$ G7 v2 X 2、打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);& x w% r5 D3 A2 D9 |' w- a& s* F% j 3、等待外部高速时钟晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp();. S' N! ^5 d5 x+ O' x+ [ 4、设置AHB时钟 RCC_HCLKConfig; 5、设置高速AHB时钟 RCC_PCLK2Config;& U. H# A" c1 e( Y' ? l; v 6、设置低速速AHB时钟 RCC_PCLK1Config;: T* w$ l9 z; k+ C 7、设置PLL RCC_PLLConfig;: q. s% M: h8 Y9 T8 G7 y& @% v( Q 8、打开PLL RCC_PLLCmd(ENABLE);$ u5 d3 P# C. _" E# H6 `3 a 9、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)/ p4 ~, e6 Q* P( h' q 10、设置系统时钟 RCC_SYSCLKConfig;7 _. M( `, Y* f7 p7 w. o 11、判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08)9 }9 T' f6 [) M% i 12、打开要使用的外设时钟 RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd() 3 U, Q K3 C7 h) e 代码实现:$ m7 H& n/ _. V: D2 X, r 对RCC的配置函数(使用外部8MHz晶振) 8 W, k9 x% o9 l) L1 E0 B1 E: ^ 7 _0 G# B# o+ ]6 y. W% X$ H+ ` 系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M% I4 F8 u/ h" d3 K8 e* H
时钟监视系统(CSS) ![]() 6 p+ U6 ?3 i$ B # z$ T' }, H# K4 e 2 E- s$ U% @5 C9 p! X$ D ! }/ H4 G$ G, B0 }8 n% f) W6 \" ? X |