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

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

[复制链接]
STMCU-管管 发布时间:2020-12-4 15:20
【STM32】系统时钟RCC详解(超详细,超全面)
1什么是时钟" h- {+ W/ L+ s: C) v. Q3 a
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。
+ y/ S. b# m0 ~1 v& _; G. J7 x" z
- I! s. d& l8 s  v3 `9 t为什么 STM32 要有多个时钟源呢?
2 ^) `8 _3 r) z
, s, U5 |- i6 |8 j
: A6 A) b$ H8 p& J+ p% c4 P
STM32本身十分复杂,外设非常多  但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费   并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树# E8 i, M7 ~/ x# Z5 g4 l
& Q6 o8 `) E7 m) B  m& i; d3 _+ d" A
总括:
( i8 M! w- h" I$ Z& o* e( pSTM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。: X% c) I6 Z7 F9 U0 a
系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)" ?. U4 g; T1 k$ b6 R; k; v$ f
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。+ S9 _1 N$ d" x% E
一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。
7 T7 B. n8 t' b5 L8 Y4 m不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。
' D' ?9 O- E! o3 d1 l4 ]  i3 }对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗
! h$ ]+ m" t4 v& q5 |  \STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因
* f7 L' r3 N' a
* ^( e$ [# }1 _. Y1 @. y
+ t" f9 w% \+ C9 _6 {7 ~
STM32的时钟系统框图* ?( z8 f8 F7 h
11.png
乍一看很吓人,但其实很好理解,我们看系统时钟SYSCLK 的左边  系统时钟有很多种选择,而左边的部分就是设置系统时钟使用那个时钟源,   / R# B2 K2 r! M; o5 z

  @9 N$ d! s2 |* V4 X- m0 P

' Y6 d2 E$ S! r  r- |: G系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率8 F* m9 Y- u9 s! P

& p# f; n7 I: x' |, I, S. l
( D' R0 e; d& P1 ^+ E& ^
从左到右可以简单理解为  各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置) Q. \' t4 ]- O: t4 T& |5 ?
- e0 t  G; ^. a2 C
( D' o7 v1 I/ X1 n5 J
时钟系统' o" |" F" \5 c4 V; u1 v
1各个时钟源    (左边的部分); ~9 F, P1 a! `9 W) V. r/ ^1 g" H9 r
STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。
7 H% \* E! M" W6 M2 a①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。7 B& Z: f& z" b/ |8 c, b" D7 x
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。2 s. ]1 n0 m7 S$ h/ j9 W! [
③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 
% O7 k5 F; [" X7 f④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。: A; H( T7 B8 Z. ^7 D
& x! O. w2 w' h1 s% j
/ F, C* ]7 b. Z; E
其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源 而独立使用 - J' }  k2 h; A' B
* C0 r1 i, o1 h4 u. d
" x  L9 ~  z! B) C
而HSI高速内部时钟 HSE高速外部时钟 PLL锁相环时钟  这三个经过分频或者倍频 作为系统时钟来使用
' _2 E- G2 a' B: G# u4 w5 j: q% n  `2 }
8 U0 f# Z& j3 y. X: ^. K
PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。  通过倍频之后作为系统时钟的时钟源' C7 M8 @+ t7 ^3 J8 _' [% _

  `# ^# o9 C  Y2 J
  R& W8 k7 i& k" G% L2 k
举个例子:Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。
1 n: g- u, Y3 w1 e0 A( e. w
7 r  [4 R& U9 e- ~  ~$ T
, O1 q8 j2 c+ J- v2 k
或者内部RC振荡器(HSI) 为8MHz  /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz
( X/ o# [& V2 x1 a: [
# X: |8 a. H$ I  N3 G. ^0 ^) T
- n0 l7 [8 @* C' `
PS:  网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟! Y" z2 c# G3 d

1 ^/ M! ?. z' Y$ ]- Y
: F* s  ~: u" ]& ]2 U
2系统时钟SYSCLK
2 b/ Z  Z6 q3 S' g" W: D, K" E系统时钟SYSCLK可来源于三个时钟源:  g# ]% b8 Z7 l2 G$ ?, w3 Q# T9 Z
①、HSI振荡器时钟
$ f0 Y2 b' B) s0 @( _1 j3 B②、HSE振荡器时钟
& D" @/ m$ E8 L6 p! {" F③、PLL时钟% [, J. n* [; Q! U) k# y) e( F- f
最大为72Mhz
- X" s5 H. f$ F
12.png
3USB时钟: a* E# i) c0 v% G  q1 v0 k
13.png
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz! k; W  ]: P' Y% W: c" ~4 u

3 N8 m  x5 h9 f/ s/ \) f
) H2 g0 L5 P3 }4 P; F
4把时钟信号输出到外部' i, {9 U$ l! L# e+ {1 H
14.png
STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用4 K9 q" `- E& G! ^7 [5 k6 b7 T

" H5 K  O# q: F* x" r4 \

0 }1 c. D! F7 [' F0 u5 |, d7 h5系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点
! j! p8 I# F, S/ M# S- j* y, i( i' ~
3 x6 g* {: P: J7 K从左到右可以简单理解为  系统时钟--->AHB分频器--->各个外设分频倍频器 --->   外设时钟的设置  M$ c2 W& l; X0 |2 e5 @

3 ~' ~" Q2 e6 Z! y: Z. J9 x
/ P# g% \& [4 `9 i0 _
右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用: , s) Q0 l: [8 t1 M

; |% p) N. w- l: Y
* E9 \$ ?: |/ @3 n5 O+ G6 p6 G
 ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。 " f) e6 ^4 j! ?2 w( D2 ~6 v
 ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。
* G+ T" C/ m, |6 h4 r ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。 ' m: x" v& r2 I  p
 ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。
! ]2 J% b7 d& k ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。
% h0 d' [' \% ~9 C
8 x/ o6 J* a4 N
+ I6 G5 e0 u4 I- |; Q
另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
+ E# F' |; U% }6 s
) R( o. l/ a2 v5 f, V
) p& P6 W0 @3 }. K! e, v
需要注意的是,如果 APB 预分频器分频系数是 1,则定时器时钟频率 (TIMxCLK) 为 PCLKx。否则,定      时器时钟频率将为 APB 域的频率的两倍:TIMxCLK = 2xPCLKx。 ; u5 Q- G4 g8 U

  @; l' Y0 c( {3 G' U
5 i* x2 j- s8 s. }& T6 c
APB1和APB2的对应外设# }# v( D' l# |( f9 r, p2 L
F1系列( n4 D+ \3 a6 V# F) ^
15.png
APB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;
5 p! W5 n0 S3 @5 w8 b% }% G/ x! [) }+ N5 v% f' e( w+ ?1 ?
' M" S1 }. M" ?+ j
而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。/ ^, q) ^' u9 U# n' c
* h; T" x, t% w4 W; y7 f, h  ?  X0 K
; M9 ?$ d" A! I; Y+ x
F4系列
) j. H. D1 |2 A
16.png
这个和F1系列类似,我们就举几个特殊的
+ U8 T* |8 {1 _  Y/ j7 `" o7 z2 b4 k

3 ~" [# y$ R! f APB2总线:高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11   UTART1,USART6  ^) ?5 z: b# E- W* n& J1 K$ l
& ^/ n5 U5 y5 J) s: z+ `4 Q+ j- N
. R$ S' b2 {2 E0 d
APB1总线:通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7  UTART2~UTART5
. {2 ?1 c$ |, ]5 ~9 Z8 B8 b) A# P: J9 L0 L2 z# z' F2 o. |
$ T( [% ~3 @. d' u! |3 Y
F4系列的系统时钟频率最高能到168M
+ J4 f7 q' C- U2 I: S6 b8 F' B. k9 p9 _: _6 W( E3 e4 c
, Z2 ^2 l5 p" \. x/ Y
具体  可以在 stm32f10x_rcc.h  和stm32f40x_rcc.h   中查看
: h1 m5 h# l" O/ x( v5 @/ ]. S' L7 n2 S! y: `3 o; S% q, h
# |" n2 c* L+ Z' l  t
或者通过 STM32参考手册搜索“系统架构”或者“系统结构”  查看外设挂在哪个时钟下,' T- F% c, ?  g, J7 K

* _1 j- P$ U0 n1 y
0 z9 i" C# E& }7 D/ O
RCC相关寄存器:
3 @% s  u; \- l2 |& z9 l这里我们以F1系列为例
( Q7 Z1 \: v% ~3 U  F, g5 F+ s
  1. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:6 O5 ]+ a0 V" F1 r
  2.   |/ U& C- z1 h
  3. 1059行->1081行。:  7 S9 ]7 y  V8 M+ A
  4. typedef struct  5 W  t1 H, i' \& w" ^7 T4 u6 N$ W
  5. {  3 i1 q# F1 \- ^0 i3 Y
  6. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  - U; ~( [) U. g1 s$ U/ R% W
  7. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定
    % l# X  ?6 R* i* D2 Y( X
  8. vu32 CIR;                // 清除/使能 时钟就绪中断
    6 F0 S( j- W8 M1 V
  9. vu32 APB2RSTR;      //APB2线上外设复位寄存器
    2 d+ l) g8 [1 J# W8 l" y8 g8 z0 _9 w
  10. vu32 APB1RSTR;      //APB1线上外设复位寄存器
    ) o7 f& o' \: D, y4 ]
  11. vu32 AHBENR;         //DMA,SDIO等时钟使能   ^/ ^0 D& v. E, ^- w# {0 n4 c6 E
  12. vu32 APB2ENR;       //APB2线上外设时钟使能 # J: ^2 ]% M: S: z. Q7 M9 g5 B. R9 o
  13. vu32 APB1ENR;      //APB1线上外设时钟使能
    0 d& Y7 k; t) }: B8 r
  14. vu32 BDCR;           //备份域控制寄存器 , i: {- x- v- r- P3 p' O7 V6 a
  15. vu32 CSR;             + j1 N- [8 Z/ M
  16. } RCC_TypeDef;
复制代码

' L$ q7 S% C  \! ^, f可以对上上面的时钟框图和RCC寄存器来学习,对STM32的时钟系统有个大概的了解   其实也就是我们上面介绍的流程,理解了自然也就能写出来
: b6 K+ p9 c! _4 k8 Z) o, ~) K9 s% a4 p- u
6 k; B# v# N. G; M4 j; C
RCC初始化:
: T3 r6 |7 }' p4 A  Q2 s$ v9 B" o这里我们使用HSE(外部时钟),正常使用的时候也都是使用外部时钟
9 _6 S% n+ ]1 a; ^% A% h
- `! M" F. m  I

0 u+ I4 {9 u$ z+ I* e使用HSE时钟,程序设置时钟参数流程:+ R' p# P7 Z4 z7 V$ N, i
1、将RCC寄存器重新设置为默认值   RCC_DeInit;) ]) b, W9 Q* e
2、打开外部高速时钟晶振HSE       RCC_HSEConfig(RCC_HSE_ON);) W0 o# X  e' t: \* i. ]% q
3、等待外部高速时钟晶振工作      HSEStartUpStatus = RCC_WaitForHSEStartUp();
& }( ~5 o1 B# t+ K0 r4、设置AHB时钟         RCC_HCLKConfig;
) `# c7 z! w: A0 V1 F" r! Z6 u5、设置高速AHB时钟     RCC_PCLK2Config;
! m& X2 m0 L, V6、设置低速速AHB时钟   RCC_PCLK1Config;+ k. p+ ]! W3 b1 R9 p( T% e9 S
7、设置PLL              RCC_PLLConfig;( l1 Y, G4 n5 A8 Q
8、打开PLL              RCC_PLLCmd(ENABLE);
8 r; L+ G) X9 y0 S' [4 ^$ c9、等待PLL工作          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)) m$ Z1 r3 ^$ J$ t
10、设置系统时钟        RCC_SYSCLKConfig;
* _1 {/ z3 l% D! ~; ^. T6 d2 f/ q/ Z11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
, M& C6 r5 l. a0 Y. j2 }4 X12、打开要使用的外设时钟      RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()( q+ x4 y# I8 z- I

& M( F  {8 X4 ~  {
" T+ [2 }2 D+ Q! I1 h9 s
代码实现:
# Y4 I$ K/ }/ k6 U  Q* K对RCC的配置函数(使用外部8MHz晶振)  
' z5 M7 e, [1 \
! t$ v+ |+ D( a: r

0 `9 R" Y1 T) W6 K  L" g/ O
: b6 q0 L- ?/ Y系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M
, ^+ Y5 c1 J+ G& R6 _' `) x
  1. * P. P! q6 B. P
  2. void RCC_Configuration(void)
    2 g* a4 d+ H$ G  o5 v6 T4 t; g; B
  3. {; @' }$ [2 Y$ [# ~
  4.         //----------使用外部RC晶振-----------3 I& x- R* B# k% t7 L
  5.         RCC_DeInit();                        //初始化为缺省值
    3 V1 b" j# M" y% K* U
  6.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟
    5 ~2 ~" Z( o6 }' w% C
  7.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪4 ^; R" u& m5 }
  8.        
    1 ]3 }# L3 e1 P) [+ T' p
  9.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer
    $ K: F' u7 w# K+ D5 a
  10.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state
    2 f6 G  c2 a3 [4 O( C; I
  11.        
    " @6 V0 N) I/ n7 y' I
  12.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK
    . S% ^+ e# ]- P  }
  13.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK
    & }8 e) x  s; f9 o$ i1 L/ K3 y
  14.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/2; t+ B; d' Z5 c
  15.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ
    ! y8 ~7 G, d. a6 C7 L
  16.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK& m! l4 J% z2 Y4 {+ d  i
  17. * {, ~. r( |: G
  18.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready
    : L0 B  A& i" \) k; L! a
  19.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock2 l# R/ T9 [# A6 A+ `4 k/ }
  20.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source9 H0 F! c9 _3 s& J- J
  21.         , D  V" R2 _0 y/ G1 W& E
  22.         //---------打开相应外设时钟--------------------2 G  D3 [0 n' Q2 Q/ t
  23.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 & ^/ D# D# V! A& {7 G$ N% C: J
  24. }
复制代码
也就是我们时钟树框图从左到右的配置,
+ |- ?1 C, {; _# `) Q+ W; f, P+ w9 N

& n/ ^9 Y+ a( F6 |时钟监视系统(CSS)
0 i% T' l! ?$ y" |* s9 n- \! t
17.png
STM32还提供了一个时钟监视系统(CSS),用于监视高速外部时钟(HSE)的工作状态。倘若HSE失效,会自动切换(高速内部时钟)HSI作为系统时钟的输入,保证系统的正常运行。
! T% t+ B: x% L- `" d9 D& v  o
8 u( |) a& V. ~
/ ]  H  t# g( h% h7 Z  T3 o

, G9 N1 W) p" u8 M) d
& _5 Q+ j5 C. J: |2 W

$ Q" |  A- A5 J5 e' W

! }( g+ u: k3 ?2 A
: L6 ~  \9 G1 \7 s$ N
收藏 2 评论0 发布时间:2020-12-4 15:20

举报

0个回答

所属标签

相似技术帖

官网相关资源

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