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

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

[复制链接]
STMCU-管管 发布时间:2020-12-4 15:20
【STM32】系统时钟RCC详解(超详细,超全面)
1什么是时钟2 F' _* f$ p- v
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。
+ ?  g/ n, ?1 X8 s* k2 i' R- \; |+ j: e
为什么 STM32 要有多个时钟源呢?! w& L3 h! t  \; X7 X
0 Y4 D* j7 S; i; k" B% V* ~' h

8 K% b8 X1 d3 ]) s7 o  e( ?STM32本身十分复杂,外设非常多  但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费   并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树, ~. R  ^6 i9 c7 [  @3 g1 K
( m' m% J; i  N" j. K
总括:2 q- r' ~' V4 A5 d$ L
STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。
' T& b& n3 D. j8 I系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)
) L* C5 V1 H) \& w' [8 N( R时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。
4 ], {0 Z6 u& T一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。
8 J, w! G( Z9 P/ m" N不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。" f. g6 [: {0 Q3 s; o
对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗
3 {* q1 y  B' c. {# RSTM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因# q& Y/ l" c& M( @0 Q1 ?* S* `

. D6 `3 ?& }6 c( i$ s% _6 t4 d, n

8 K9 B1 n6 o3 K2 D5 R3 VSTM32的时钟系统框图
4 Q7 w% Z- E& y
11.png
乍一看很吓人,但其实很好理解,我们看系统时钟SYSCLK 的左边  系统时钟有很多种选择,而左边的部分就是设置系统时钟使用那个时钟源,   
4 |' E. y- o9 e/ z& S  B# i9 ^/ i: a8 g: v- a% [9 [
% B" O: U  r, T; u! M1 Y5 J
系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率
: r) l  h5 Z. b8 \9 R  l, Q
& x' N$ t9 z# f- F. x+ {: G% u
8 `! O; p3 C* W' Y5 T# w* f
从左到右可以简单理解为  各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置
+ ~; v8 {7 J; ~1 R
; K5 d  g0 w+ Q" M# h' ~7 }
" n1 X2 H+ v. d$ F% S
时钟系统! J! c" U2 `% }3 o, H
1各个时钟源    (左边的部分)$ o/ Z: m. p* Z: _/ A
STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。) F/ {! N( Q# G% u2 @. R
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。
& w: g0 }+ U" O1 _% d* ]②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。1 b  K$ E0 R0 Y
③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 
. j0 G. f6 o1 u# R$ X$ ?④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。1 }/ Q6 a& v5 w# }) |) @, [7 Q' A
$ a& h* y% ~/ F3 T& y

* ]# U) u! I9 h% v  o$ d+ {其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源 而独立使用 # p$ g+ E6 F5 D9 k4 e

: E3 C1 P& M! r* S  B" H
/ y; Y# b# F& h1 e6 O
而HSI高速内部时钟 HSE高速外部时钟 PLL锁相环时钟  这三个经过分频或者倍频 作为系统时钟来使用) d4 f8 W' S: R. N5 N* F0 [0 i

' ~/ N: @; I5 q+ [8 B: Y) Y3 h

2 E1 w8 T7 T+ d9 x+ H3 fPLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。  通过倍频之后作为系统时钟的时钟源
# p- [' \( ^. q: _4 o) I' i7 ^) O' s6 J9 u' |- x

" y0 n& f. X# Z( T, |举个例子:Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。/ S: j) \) p3 l0 O4 S& Z
' M# X6 }( a# E& Q- y* ^
/ a0 E+ T5 K  m( `- Z0 N( W8 h. y6 s
或者内部RC振荡器(HSI) 为8MHz  /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz0 ?6 a, m( y/ n5 r$ l

# T9 Q6 C& \2 P/ @/ p9 H

- ]* j+ m; t/ p5 }PS:  网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟
5 f! i3 B$ \5 `9 R2 r
9 L* j4 J2 K: ?) ?6 E2 \

- D. o1 a$ e& {7 S( F0 S) N2系统时钟SYSCLK2 L, L/ ^" E5 D* h
系统时钟SYSCLK可来源于三个时钟源:
1 |) d2 h) K9 l5 c! S/ r( ?①、HSI振荡器时钟
- a) ?1 o1 D$ d" k# z②、HSE振荡器时钟
, L6 r: C4 X& N3 V6 T: k③、PLL时钟1 Q& R& _4 o* q  H' m* ~: T# ?
最大为72Mhz
% }* ^9 l$ L  A4 D! p
12.png
3USB时钟+ \; c5 f. X4 g! `8 D4 j
13.png
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz, [. E0 {0 _; T: l- Z3 a4 ^+ a" d9 Z$ ~

; U+ x1 Z- e8 _$ s9 ?) Y( E

. }& v- L6 j% ]9 F4把时钟信号输出到外部( P7 d! R* t( L: j, b+ l
14.png
STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用
6 X' c+ e7 u$ L3 Y8 w2 Y
; i* c4 S7 {9 R0 \

! Y1 y; T: {6 [! V5系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点9 k! g$ x) v4 M9 U
: ]0 `: [, d+ b2 J+ [: y
从左到右可以简单理解为  系统时钟--->AHB分频器--->各个外设分频倍频器 --->   外设时钟的设置
- r! b; e) U4 i9 [* L% z( ]" ~6 V' O

9 e3 v2 `6 n. |! p; \$ @右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用:
" K( x0 q" ?' U" ^' h/ S- P2 m
: B  s7 n9 o. H* l  s
* T% g- L/ u" P5 C# M, m. ]5 v
 ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。 & x3 J" b2 ^; H  }$ s
 ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。 8 j, O" F3 k2 {- Y1 F
 ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。 5 Z4 v. t/ O5 @# Z& [: r  Y, {
 ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。 * W- r8 w7 ^4 L; i3 {3 c
 ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。6 W* U6 L1 [3 j7 B' V

/ M) y9 B" y, J- Q+ Z5 ]
: d" e# ?2 ?( p% Q# _
另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
0 C7 ]- A' S9 f
6 k* F3 ?* g3 t% K8 C5 R) h$ u- U
) }% H1 O3 a- o' a5 i
需要注意的是,如果 APB 预分频器分频系数是 1,则定时器时钟频率 (TIMxCLK) 为 PCLKx。否则,定      时器时钟频率将为 APB 域的频率的两倍:TIMxCLK = 2xPCLKx。
1 o( x9 _5 R, A) G
/ J3 Y4 ^' \7 B) d* G
$ H7 x, O; I3 [0 q
APB1和APB2的对应外设
6 \* C3 P/ {3 jF1系列
8 l) e  Y- ^  l6 }: Y. J
15.png
APB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;
* \, ^4 s. A5 ~! }  c% j# D% v/ o* R$ W# U; |4 l7 J' z
- o) l, g  @3 E/ D9 W' n
而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。
0 L( P7 C4 r& Q# Q6 Y/ K: E
4 D, P! L. G( S2 W$ R

0 v* T  r1 ~/ P  u- fF4系列
! k0 `# k/ U: u4 f8 Y) r
16.png
这个和F1系列类似,我们就举几个特殊的
# }1 j5 C; M+ h& v/ `4 C( e. Q- _3 q# G) G( s! B' }
% T9 x. \, V( ?
APB2总线:高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11   UTART1,USART6% X8 Y3 u: d1 b' [; M) g
8 \, d( o9 z6 N# O! m4 g

2 d; H$ u" i9 d& _+ | APB1总线:通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7  UTART2~UTART5# d1 r7 M  b9 }  E
7 K$ G# [: }% [
- _" E, y# O0 F5 A$ z4 @
F4系列的系统时钟频率最高能到168M
& S4 L6 V  Y" a. N" r# m% U+ I( }% N' |
# ]+ x! k7 v. g
具体  可以在 stm32f10x_rcc.h  和stm32f40x_rcc.h   中查看
, }# ^5 w) [( ?! u
) b: h& C' {( X
, q/ Q3 l" `. ~
或者通过 STM32参考手册搜索“系统架构”或者“系统结构”  查看外设挂在哪个时钟下,2 F8 c; i2 G2 {3 d3 B8 g

  }6 X/ y; F! C' J7 k. s
: e2 I2 @  a( U/ {/ x# e
RCC相关寄存器:
+ y9 [+ d* X0 L" c. Y) M这里我们以F1系列为例  m4 L& d4 d; ]. o
  1. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:6 D* K# n8 l6 P  `0 }
  2. % w9 R/ h) ^5 ^  `5 x- g
  3. 1059行->1081行。:  
    . k3 D4 {$ m/ I+ K5 f9 Y: G" A+ j
  4. typedef struct  
    ) L* o" [% `$ L2 a. p  \
  5. {  
    8 V9 z% h' M2 U& v# ]* ?
  6. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  
    ; l( M5 N% n" k8 r+ C( L
  7. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定 & ?0 P! B0 d2 S$ P( f2 d6 J
  8. vu32 CIR;                // 清除/使能 时钟就绪中断 - N" V2 ~9 h; g2 J
  9. vu32 APB2RSTR;      //APB2线上外设复位寄存器
    & X3 |# r! B3 B
  10. vu32 APB1RSTR;      //APB1线上外设复位寄存器 : v) \& i$ H8 T4 ]
  11. vu32 AHBENR;         //DMA,SDIO等时钟使能
    4 ~  N) s& L& e: y" v' j
  12. vu32 APB2ENR;       //APB2线上外设时钟使能
    ' ^1 A1 m5 g3 M% L" E& g% h
  13. vu32 APB1ENR;      //APB1线上外设时钟使能
    , N8 r% f1 ?0 _. Z) n9 ~# t
  14. vu32 BDCR;           //备份域控制寄存器 , R. h0 N5 _+ n$ _- E; K, }: v
  15. vu32 CSR;            
    " M" B! R: s5 o
  16. } RCC_TypeDef;
复制代码
2 M, s, `6 r+ W( }& @4 n
可以对上上面的时钟框图和RCC寄存器来学习,对STM32的时钟系统有个大概的了解   其实也就是我们上面介绍的流程,理解了自然也就能写出来
% L* r+ p- ~  q1 k& V2 S
8 w* b4 s1 }- i  K. X4 r
" F& h2 f$ B6 W; @6 U4 D
RCC初始化:
9 r, B6 K6 h+ c5 `6 D5 @/ M3 f这里我们使用HSE(外部时钟),正常使用的时候也都是使用外部时钟
* |8 e9 d0 ^) k! W, j' y0 Y1 r1 v4 Y, _$ j
! }' F* H! X& L
使用HSE时钟,程序设置时钟参数流程:
# M3 D% k# K3 B3 V! v1、将RCC寄存器重新设置为默认值   RCC_DeInit;
7 g  u  B- i1 W  u2、打开外部高速时钟晶振HSE       RCC_HSEConfig(RCC_HSE_ON);
$ N& d* P! ]! L# O7 c2 I3、等待外部高速时钟晶振工作      HSEStartUpStatus = RCC_WaitForHSEStartUp();
) n7 F. R4 `" O0 o$ f% I+ I. E4、设置AHB时钟         RCC_HCLKConfig;: v6 l/ w! H- A% H# @  f, V% p
5、设置高速AHB时钟     RCC_PCLK2Config;5 l% ]/ q+ }+ j
6、设置低速速AHB时钟   RCC_PCLK1Config;1 h" G! O* I; N  h, A. s
7、设置PLL              RCC_PLLConfig;4 C' d  L7 @6 [4 U% t* G
8、打开PLL              RCC_PLLCmd(ENABLE);
( q1 s0 h! o# R4 i# d% h9、等待PLL工作          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
& v3 U4 `2 C. j9 g1 y10、设置系统时钟        RCC_SYSCLKConfig;5 O2 b) u  y4 y$ ?/ k  k
11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)3 Y7 C9 ?! h* ~5 B
12、打开要使用的外设时钟      RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()
2 O! m  d' A% L
" i. Y: G* h9 z2 i3 Z3 X

3 x5 }' W* N4 D* F# k) m; ~代码实现:! H! o6 a6 E- K) T% R4 u
对RCC的配置函数(使用外部8MHz晶振)  
( u. C5 H# @( s! S0 E- b% ?% N4 D' ^* I6 d8 S: V1 E8 q- q! I6 T
1 l. N. i. O6 w5 B

6 ^( H- D. T+ c( B系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M: S4 x- j! X4 Q, n7 r$ T1 ?+ q
  1. 8 b6 q9 M$ R% m. u) Q
  2. void RCC_Configuration(void)) Q2 W/ ?. x1 P; ]3 o
  3. {5 n  h' s3 h. |+ x- n" j& U
  4.         //----------使用外部RC晶振-----------
    * W3 q; ?# H% t& u/ a7 z- q6 U3 V: V
  5.         RCC_DeInit();                        //初始化为缺省值
    ) ?/ j* T9 G$ J, L
  6.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟
    . _% B5 Y; l9 ?4 ~* D, }+ ]7 A  V8 h1 l
  7.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪; i5 ]; P- \2 I8 Z0 Y
  8.         + C1 ^/ A9 j! B8 M
  9.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer
    6 b* e# y7 }% n0 a
  10.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state4 `! s( f) L' ?' G" W1 m
  11.        
    ! m- e6 ?$ T8 D$ R) A0 h
  12.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK$ B- L6 q! L6 r0 T
  13.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK0 k3 k6 Y$ b# C  g; p4 w
  14.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/23 f( C5 ~/ o7 H  c2 ^8 c4 E( @
  15.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ
    7 m9 z" A2 X% Q; Y8 h& ^/ n
  16.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK& d7 _$ t4 O- {5 O2 N# v

  17. * N; S: Z! n1 R, d5 x& F1 A. q
  18.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready
    & O/ T* {7 I* v/ s% {+ G
  19.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock
    ) B! j4 b1 [0 z
  20.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source* n7 `- O2 x9 H& k* c; Y+ k' K
  21.        
    # N/ ~4 M; N- s# y
  22.         //---------打开相应外设时钟--------------------
      k$ Z( q8 c) t% o% s. @
  23.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 
    " M9 Q0 E1 T2 V" ?
  24. }
复制代码
也就是我们时钟树框图从左到右的配置,1 U, ~" m$ J, a  j: ?0 [0 x8 k5 R

, |  c, K# g( ~) W
5 w8 y) x$ ?. |9 O
时钟监视系统(CSS)3 r+ `; m  T% e9 T2 r& r2 H$ ]
17.png
STM32还提供了一个时钟监视系统(CSS),用于监视高速外部时钟(HSE)的工作状态。倘若HSE失效,会自动切换(高速内部时钟)HSI作为系统时钟的输入,保证系统的正常运行。
: U0 T( c$ M- i1 M9 e* k4 D1 ]& A0 i$ ^( |1 D4 u$ y: w6 w

7 a. {7 q- r8 i6 g$ e% s: B
4 ]/ A) f& z0 N2 C3 U, n

# F9 A6 l: |' k' S. F* `& Q/ A
2 D3 e0 [6 ^- ~- a# g

: n) p, l3 e1 R) ]% Y& [  A- _* r  v& H6 x; ^9 |; h
赞 收藏 2 评论0 发布时间:2020-12-4 15:20

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版