你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32】系统时钟RCC详解(超详细,超全面)

[复制链接]
STMCU-管管 发布时间:2020-12-4 15:20
【STM32】系统时钟RCC详解(超详细,超全面)
1什么是时钟
: D5 s) b8 a# b2 @/ ?9 E时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。
  a8 ~! O. _1 P: \$ Z$ ~
" I/ R3 v* o) Q5 X为什么 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 R# r: S  B1 p6 C系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)0 y' i7 X# t3 \) |
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。- U( i) x4 |) ~# R1 k) O, Y5 E- y
一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。
5 D2 p" n* ]' r4 g- H, J! p8 S& q不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。
* V5 X6 r  T' h* b对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗, V0 ?- g( R+ K) T5 n: q3 G
STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因
6 t: c% |0 P: o
6 p) ^& b2 m# j: S0 C7 C2 Q
) C/ H. ~$ A* g; I
STM32的时钟系统框图
- ^& ?/ D8 Y+ i( ]5 a; r
11.png
乍一看很吓人,但其实很好理解,我们看系统时钟SYSCLK 的左边  系统时钟有很多种选择,而左边的部分就是设置系统时钟使用那个时钟源,     c$ t& s4 ^" O' H( A; H
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

& p0 o; x  s3 }

4 J7 O4 R# \' Y; [从左到右可以简单理解为  各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置
' ?$ @$ s6 a) g2 U; m0 A1 K
8 W& H8 W; t+ {! ?8 @3 p
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,提供低功耗时钟。 
# U: }' ?9 b, ^. O. Y: _1 r3 u④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。7 y& @$ x4 N' V' d6 _9 n

- b' W& u- @2 X3 I; C* {
: 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锁相环时钟  这三个经过分频或者倍频 作为系统时钟来使用
; V+ d% K% v) }) O  ~0 |& h. I6 a7 d$ q! |! ]

) K) u! F# O2 F) uPLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。  通过倍频之后作为系统时钟的时钟源
) O# J; I& p+ h8 g* T9 N
. H9 C9 F$ O% V, Q
0 N! E, C7 e1 p, L
举个例子:Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。
  J/ s0 K, @* X. |9 G  N
( A( }- m2 e5 X3 p9 c9 R

* [1 t0 k+ f. G  m( @8 u" p9 r  Z或者内部RC振荡器(HSI) 为8MHz  /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz
( Q) C4 q; J# r" G6 }  E. P/ _) q
* e) f+ E  Z# @, z
, q" V/ m' u% ~" _4 c$ i. W$ m
PS:  网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟
" w2 o3 d/ {/ V7 H+ T2 m
  d2 V. w; _6 a8 ~

% h# M2 T/ m1 n6 @; r8 [& k2系统时钟SYSCLK7 v! B* ]! u  l; c
系统时钟SYSCLK可来源于三个时钟源:0 E7 m' u. E9 _: \: u
①、HSI振荡器时钟
7 X. \# f  f, u/ H1 S②、HSE振荡器时钟" t! M3 v! t; t
③、PLL时钟
) f! x6 t. R2 _) s! [最大为72Mhz
7 r2 p$ o! \7 H. O
12.png
3USB时钟
, z4 ?/ B- O( \5 z+ u4 z
13.png
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz
- e4 m. J' J8 ^. |/ G: T
5 S8 N1 d5 e6 Y' y: ^- x

" F6 y; K9 c/ _) ^# b) u4把时钟信号输出到外部
; [  S# @7 P$ @5 G6 P  O" L
14.png
STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用6 G$ f6 m4 D! ~0 k/ l: W  R
1 D! N7 Q( I# T  R8 p
! R1 Y9 f* z8 ?5 u' z
5系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点
+ {! \; k- c* O
0 Q, m' U/ X/ S8 z8 `% A从左到右可以简单理解为  系统时钟--->AHB分频器--->各个外设分频倍频器 --->   外设时钟的设置9 S8 H) s' i1 h0 e$ \

- ?7 `% ^  ^1 g3 z

% q2 `. E7 m3 n6 L右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用:
0 f, f6 P, P/ `& M. [) R3 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的系统定时器时钟。
7 K3 {5 |+ b$ A% _" b8 h9 @3 p ③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使用。
2 b9 x  l7 h* J. i$ o7 k0 n. [6 k
3 ?. x  G: [- G- q/ ]9 }
6 Z) r% l1 E+ @! J5 B# U
另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
) Z9 s  w* O1 L% c4 O% _) \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

+ ~$ Q! I! O5 _" ?/ y$ z! a( i4 o

) k) H( r  A! G  [% \. T# z- G, |APB1和APB2的对应外设
! Z! u" B: i+ ^9 [" ^F1系列3 `7 {' w$ I, d
15.png
APB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;! H" {$ Y( T6 m
* }' 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 |

, x: M5 ?/ T- D: {9 u! O7 Q8 wF4系列
! r4 `1 P3 i- ?1 t7 Q
16.png
这个和F1系列类似,我们就举几个特殊的. R+ D3 S( f7 ^( ~

$ l1 S5 f) M& k, y% E: M2 l! C
: Q' o7 A* P# w+ h
APB2总线:高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11   UTART1,USART6
  I- \4 Y$ y0 K
. U0 g$ }- d! t5 l

# S" u0 p+ Z1 G# N 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   中查看
) g9 ~( ~, T7 z" ~" w
- ]+ T2 n* Y$ v7 M- C
$ 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
  1. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:& Y% ~) i4 V' h  ]! ?

  2. * B5 n6 P, g. B, c1 C0 M
  3. 1059行->1081行。:  
    ; d3 [& a4 k; m1 h. R0 ~
  4. typedef struct  ' B. x! _% W0 g$ J
  5. {  
    8 V; V1 K" c- h1 A8 A
  6. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  
    3 \" _) I+ p: z) F. g3 U
  7. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定
    , J" M5 M- ?7 s5 B
  8. vu32 CIR;                // 清除/使能 时钟就绪中断 . M$ b$ e! ^' L' U6 J# O/ o. g
  9. vu32 APB2RSTR;      //APB2线上外设复位寄存器 % V0 _% {5 |3 C; [0 l! ~8 F1 e
  10. vu32 APB1RSTR;      //APB1线上外设复位寄存器
    0 z3 b7 l4 n2 S( L' u& L! Q: ]
  11. vu32 AHBENR;         //DMA,SDIO等时钟使能
    ( C! \. U& W5 C" K- B" ^
  12. vu32 APB2ENR;       //APB2线上外设时钟使能 2 P) T3 U" E  X! F
  13. vu32 APB1ENR;      //APB1线上外设时钟使能
    4 L  N  b* V7 G" _
  14. vu32 BDCR;           //备份域控制寄存器
    " W% ]" V4 I& [. O- E6 P" Y
  15. vu32 CSR;             " U8 z, k1 t1 P4 u; X
  16. } RCC_TypeDef;
复制代码

6 {! e" e- y5 _+ t6 g5 T/ C9 ~8 {可以对上上面的时钟框图和RCC寄存器来学习,对STM32的时钟系统有个大概的了解   其实也就是我们上面介绍的流程,理解了自然也就能写出来
3 u2 T! u- ^: U' F- ?$ G1 ^+ C# J4 @9 u" k: y4 h, [
. T. e' \6 [* x: [" y
RCC初始化:
; X" i  U0 A1 M这里我们使用HSE(外部时钟),正常使用的时候也都是使用外部时钟2 I  K/ c# \4 o0 P6 D

" t5 Y' q6 l7 @1 o" {' z3 t

& Y2 T8 Y9 l) m* o/ h使用HSE时钟,程序设置时钟参数流程:
* T) O4 A. x3 R  ?6 k1、将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;
7 N0 j" |. Y* X  \6 R0 u5、设置高速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 f# Y' J$ y9 J3 U, Q  K3 C7 h) e

& R( H+ b9 n9 Y# ?! b% s! V! ]! I代码实现:$ m7 H& n/ _. V: D2 X, r
对RCC的配置函数(使用外部8MHz晶振)  8 W, k9 x% o9 l) L1 E0 B1 E: ^

! r( I' E4 x/ `+ J$ B$ n
7 _0 G# B# o+ ]6 y. W% X$ H+ `

5 c# `: c, G. Q4 ]系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M% I4 F8 u/ h" d3 K8 e* H
  1. 4 |" r# ~2 m6 ~; T" t
  2. void RCC_Configuration(void)
    ( I& l  E  Y6 O0 V5 u
  3. {& V/ E- {0 H: K, x  l
  4.         //----------使用外部RC晶振-----------
    / N) G! Q! W4 V, H2 T; G* O
  5.         RCC_DeInit();                        //初始化为缺省值
    - J1 J; d" p4 U) u- `! ~& N# B: P
  6.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟
    - T6 m& p- w" u) ], l( Z/ c0 h
  7.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪+ S/ F! W& Z/ R3 a% ?% @
  8.         7 C* o- V3 `" _- q4 l
  9.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer
    * q* u3 V, B' f. D1 P6 W
  10.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state
    2 n0 Q; e- t. m+ k
  11.         9 @% r0 e1 c0 I. j" [: ]: N
  12.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK& n. @% h8 n( I, z) K
  13.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK
      x3 M' _  r9 X- d
  14.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/2% h8 R% z: N7 i0 i" x, V
  15.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ; R9 n, j8 I! ]
  16.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK# \4 h$ L. q8 N* [: ~+ k. l4 c

  17. / m" C4 H3 j* P! _1 a! O7 \
  18.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready
    ' v, {' T) A$ D  a# d; b  [3 G
  19.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock+ A2 R; V6 m% Q) Z$ E9 `
  20.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source
    " t: |) R% T8 u" |1 E
  21.        
    $ {8 v+ v1 J" Y0 {( A2 F
  22.         //---------打开相应外设时钟--------------------4 N$ i+ v" z$ y% Y7 m# L4 x% i
  23.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 
    ) n7 ?) a9 }4 g! A& G) o, I
  24. }
复制代码
也就是我们时钟树框图从左到右的配置,, d4 M' S! t/ j- q

; A, N; b+ y, m4 G  c7 c

4 i7 g! Q! \3 v8 ?/ o时钟监视系统(CSS)
4 I; D! _0 V3 l+ l
17.png
STM32还提供了一个时钟监视系统(CSS),用于监视高速外部时钟(HSE)的工作状态。倘若HSE失效,会自动切换(高速内部时钟)HSI作为系统时钟的输入,保证系统的正常运行。
4 p6 M$ v4 @! U! @0 f# E4 a6 p+ U6 ?3 i$ B

) R# b7 R' [! y% t3 E# z$ T' }, H# K4 e

7 V' S8 p6 B) \1 @2 E- s$ U% @5 C9 p! X$ D

" y# b4 A; B$ W/ x6 F! }/ H4 G$ G, B0 }8 n% f) W6 \" ?  X
收藏 2 评论0 发布时间:2020-12-4 15:20

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版