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

【经验分享】系统时钟RCC详解(超详细,超全面)

[复制链接]
STMCU小助手 发布时间:2022-3-24 23:43
1什么是时钟  D/ [3 ^2 O/ x8 |- w  N+ V
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。* N0 N6 H& h' b+ Q% T% I, \
& @) Y7 \3 K! m5 |! p2 x2 j9 h: k8 F' A
为什么 STM32 要有多个时钟源呢?+ J* L6 r5 U6 b8 z

) a* i- V. p1 p6 k7 o  uSTM32本身十分复杂,外设非常多  但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费   并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树4 ~& X3 o6 b8 p$ V- d8 g" [% ]5 n$ S

5 G# P' n  W. B/ x' i, V总括:
( O2 n' N. t" z# |* L% B1.STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。
6 i. Z; A3 C' Y2.系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)) r# K: |$ ~# Q7 q
3.时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。# g5 ?" L4 F9 S1 M! E9 v2 i) b
4.一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。- O( G* U6 e! k. Y! @; D
5.不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。
, @/ f: J; t, Y对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗5 E$ T9 c  u# Z$ N: f. ?9 \7 M
6.STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因3 X& |, G' K. p+ j
# u+ i, n/ @4 t
STM32的时钟系统框图/ ?( M- n; K, m, F! M$ H; B, Q7 E

: T" Q: t0 n6 }6 t 2019080810214187.png ' w* J$ O& P! S" t
: G! Q5 M" F' l! E# g3 ^
乍一看很吓人,但其实很好理解,我们看系统时钟SYSCLK 的左边  系统时钟有很多种选择,而左边的部分就是设置系统时钟使用那个时钟源,   
" |: f! [& b5 z6 ^
& [, l; d$ X, x& B: C& b系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率9 C( ~" u/ L* I5 q1 k
- h; X& B/ D& b6 G- L9 t2 k+ x
从左到右可以简单理解为  各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置
. h1 d% d% I% U# Q1 H% ]3 E
4 m7 B0 ?1 y; W/ y& W% h( S3 J6 R- z时钟系统

" N3 i, o9 g* i$ [" i1各个时钟源    (左边的部分)
. D/ |* g+ ?! z
STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。- p' b- [, F4 d
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。$ E1 F, c. T; `" ~/ a
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。, w! e! z' i/ }) y4 ]* P0 v
③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。  7 y/ w; j) i+ q" p, ]
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
7 q& o! d# N! W2 Z9 j  T; m0 p3 E9 T6 {6 h1 R- r) J/ h0 d
其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源 而独立使用 * \7 p9 h7 g2 E

- V1 J4 N$ \3 f* H- ~! f而HSI高速内部时钟 HSE高速外部时钟 PLL锁相环时钟  这三个经过分频或者倍频 作为系统时钟来使用
8 O) l- c" O# k) L
3 K/ M0 H* n: G5 t4 P! nPLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。  通过倍频之后作为系统时钟的时钟源
2 M! K/ w  h: C; p  q0 e6 Q! O4 J
$ Q( O( Q2 H; d举个例子:
Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。
% P  B2 G, d- g8 J- K. f0 Z" T. ~2 W* d* M
或者内部RC振荡器(HSI) 为8MHz  /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz
9 x0 T- j2 V  k3 q; D( t
: n; d- F7 H2 a- H3 J- {PS:  网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟
; H! ]& Y4 l" n3 d9 X6 t$ i. d( ]' P$ x* A3 p1 e3 j  i  Z" b* Q
2系统时钟SYSCLK

3 [$ f& _2 @0 s. U8 H, z系统时钟SYSCLK可来源于三个时钟源:
' \  z' ?! }1 Q3 L0 g' z①、HSI振荡器时钟
2 Z$ ?- S. e# @4 y0 A- G②、HSE振荡器时钟
9 c9 K8 d& E" W2 Y③、PLL时钟
, U* g9 m* o" t# W最大为72Mhz( J  W7 w- B# \$ A3 u3 D8 W

4 T9 {; m, g+ j9 H9 E 20190808112745842.png
3 i$ x4 T+ q# t
& O9 d; n. C9 d8 n
" P: K' y3 S* d0 p4 o9 I. c3 l3USB时钟
$ H2 Q2 c( C: `
0 g2 `$ f0 S1 d 20190808112421863.png
$ @; g. l0 a9 a9 {3 L  K) m' A# L5 z- r& \9 `- w# [
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz) X2 Z3 j# r+ q1 ]7 ]
9 T2 S" a6 D: _$ i+ A
4把时钟信号输出到外部1 w8 j; n' ?/ S5 j* t( ?  r% n# |
5 U3 ~$ O3 |5 \5 x; W' k, W. ~
20190808112900726.png % Q  A) A6 }: A9 [

* _" O* s- [; YSTM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用4 e1 }4 u/ Y$ {& h2 W5 t
/ R! V9 B, p1 z/ F! C$ h
5系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点
' _" O) l- j, A9 A
, Z$ J) \! z8 H1 l3 s$ C
从左到右可以简单理解为  系统时钟--->AHB分频器--->各个外设分频倍频器 --->   外设时钟的设置
& |/ h5 S, m% r; _
7 h  u+ X; F% l# h右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用: . F) X/ D) e- R% ]& ?" b+ M
+ D" @' L6 t/ k, K9 _
 ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。
: |. a0 e  M8 k- X
0 d7 x3 \' B! R! W8 {& s ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。
+ ]3 G6 V& y- D9 `7 {
+ L, X7 [: x* u! G  U ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。 : V4 k3 J9 `1 c9 S

5 s+ a: h2 A7 n1 M4 Y1 e. _3 S ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。 9 p$ m/ y1 f3 q2 R/ d* |: c

, M/ G) l7 ~& z) o( h ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。
; U  k. C8 j& D% p" c$ k8 \7 @7 v% q4 Q! J- P0 Z$ x
另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
" K1 P  V3 J& q$ B. p# p, j2 V8 w1 x
需要注意的是,如果 APB 预分频器分频系数是 1,则定时器时钟频率 (TIMxCLK) 为 PCLKx。否则,定      时器时钟频率将为 APB 域的频率的两倍:TIMxCLK = 2xPCLKx。
  L6 l7 O9 x1 P0 [$ \) E, [' q: u9 g/ k/ Z, _" o5 r3 U
APB1和APB2的对应外设
, `# I! t! b) o: U5 D3 u  H) EF1系列

1 t: Q: K4 S/ p2 W$ I
4 q. m, Y, F6 X8 @, Q2 c 20190808142757981.png
4 t$ |) C5 S+ G( _; G
( W! X4 e+ B" g! u6 G2 @! mAPB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;* G# {; N" Q! x' C  f
9 B# _; [. E; h) f! p; H
而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。
9 Y% G7 u' h0 K7 k# e
, j" |. y9 h' i1 y" T* i( J5 `; u" KF4系列
( a  r( k8 H4 N3 }! a
! Z$ ~  E3 k* y; A& q  O ~_6BOG1]QD7K$@6ID3ORORG.png
$ F& Q4 E% t# i) d6 D4 X. W. C! ]" ^
这个和F1系列类似,我们就举几个特殊的1 D+ i0 Q+ ^3 V+ l% h+ t
9 ?# ?# l2 {" n; c$ O- V: l& H
APB2总线:高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11   UTART1,USART6' E5 B, ^( H5 l& i$ b7 s/ r. T2 O' w6 T
9 b2 I# G% S* `- a* n! F8 J0 m; X3 J
APB1总线:通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7  UTART2~UTART5
, d" W" d9 ?' f
8 y, ?7 e% c' Q) Z* l" @& JF4系列的系统时钟频率最高能到168M4 ]  u% x" Y3 w5 x
! T9 {8 x) q& H+ K/ m2 Q
具体  可以在 stm32f10x_rcc.h  和stm32f40x_rcc.h   中查看
) k- S- J6 t  b! P9 L" z* X) |: ], |% S, \* A, p! U5 U6 l! i! s
或者通过 STM32参考手册搜索“系统架构”或者“系统结构”  查看外设挂在哪个时钟下,
4 ^1 K. P2 h1 X2 p* h. a0 Y* e
  W% S1 [- ]% i! p0 X: MRCC相关寄存器:
6 S' H5 y1 e; W! u' r- A. m& O! Q2 M这里我们以F1系列为例4 b( o! N4 n$ R* S( N9 T9 }

0 o. o: }: V2 U9 _
  1. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:$ W" t. F: {8 b7 D! p$ ?

  2. - v9 Y* b! V  x' {/ r' x" D
  3. 1059行->1081行。:  
    1 M' }! F( q9 D3 p8 n
  4. typedef struct  
    3 C' s4 P+ p  Q2 B
  5. {  
    , N. w, k5 d- W! s
  6. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  
    ! H" L9 A* Z0 \7 l9 S8 `/ s' q
  7. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定
    4 u( Q9 U, L5 s! \1 q# i; t
  8. vu32 CIR;                // 清除/使能 时钟就绪中断
    1 H: e9 A  l: C
  9. vu32 APB2RSTR;      //APB2线上外设复位寄存器 / ~" l% o' M; f( Y8 L
  10. vu32 APB1RSTR;      //APB1线上外设复位寄存器
    / ~' ]* @. R8 @: u+ H+ f0 `% e
  11. vu32 AHBENR;         //DMA,SDIO等时钟使能   N" [. P- T4 J* L8 P9 H
  12. vu32 APB2ENR;       //APB2线上外设时钟使能
      w, n1 _3 Z6 d" O# n2 M
  13. vu32 APB1ENR;      //APB1线上外设时钟使能 / S* S2 @, |. j% p, R8 H6 j  @
  14. vu32 BDCR;           //备份域控制寄存器 4 ^8 S; X$ J4 i- N4 N0 ]
  15. vu32 CSR;             7 s/ G$ I5 ?0 ]' p3 K6 U1 g
  16. } RCC_TypeDef;
复制代码
( [, w* Z& I0 C4 {4 m: i
可以对上上面的时钟框图和RCC寄存器来学习,对STM32的时钟系统有个大概的了解   其实也就是我们上面介绍的流程,理解了自然也就能写出来) u+ G" v' |% E; V! `+ G0 v

4 d) C5 O6 v. _! E$ W6 gRCC初始化:
; ?4 ]$ |- w/ h  B8 S这里我们使用HSE(外部时钟),正常使用的时候也都是使用外部时钟$ X* u. Y& M6 G5 E- q* b

# {/ O0 s. |- z/ c8 o" J使用HSE时钟,程序设置时钟参数流程:  K+ r7 p1 e# n. K' T" g
1、将RCC寄存器重新设置为默认值   RCC_DeInit;8 U# ~/ Y. b; |3 L$ d/ b
2、打开外部高速时钟晶振HSE       RCC_HSEConfig(RCC_HSE_ON);* C, p6 I& q, `/ Y0 ]: s
3、等待外部高速时钟晶振工作      HSEStartUpStatus = RCC_WaitForHSEStartUp();& o2 Q) F9 t6 ^) P
4、设置AHB时钟         RCC_HCLKConfig;. D# \3 A* J. d6 A( T0 t
5、设置高速AHB时钟     RCC_PCLK2Config;# D1 @  W- ]0 O4 ?  V) l2 S
6、设置低速速AHB时钟   RCC_PCLK1Config;- i- w/ S  Q  E% h
7、设置PLL              RCC_PLLConfig;
- V7 y- o/ q$ U8 d7 W6 o8、打开PLL              RCC_PLLCmd(ENABLE);
5 g4 Z) b6 B+ o+ T% F) l9、等待PLL工作          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
$ p6 I, `- p6 q: c10、设置系统时钟        RCC_SYSCLKConfig;0 \4 z7 A4 H7 x1 h& y7 Q, H
11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
- I9 G6 n) J- y. c12、打开要使用的外设时钟      RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()
( Q4 V3 _7 A. H# B
! X, O% T* s# P: I代码实现:
; A( {, Z5 v" y) O' K对RCC的配置函数(使用外部8MHz晶振)  * \* q4 E3 Y" n2 `" R4 T1 L- F

) D5 C3 r0 ]3 H% L系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M
- F3 Q% O: X! J
7 v$ f1 Y& k1 a  [$ \( F8 v0 e
  1. void RCC_Configuration(void)- |/ J* b; A  `
  2. {9 i2 ^0 D3 V% g+ P
  3.         //----------使用外部RC晶振-----------
    8 [  U. b# F, Y" S: D* G
  4.         RCC_DeInit();                        //初始化为缺省值
    - Y$ H7 y: a- n6 [
  5.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟
    ) c3 v/ s+ a+ B
  6.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪
    * L9 y0 c1 d+ c; H- Q+ O0 N
  7.         $ ]. O  |6 p  J: T) O; p+ v# ]
  8.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer
    8 W/ T, w2 {7 _: V1 `3 Z' `
  9.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state
      A) [) L% J8 I# `
  10.         
    ' p( ~1 G* Q' P5 y# o2 H
  11.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK  z# ^. |3 b) {# Y
  12.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK
    3 B7 |4 f3 D/ z7 q- ?8 k
  13.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/2
    3 s/ h* v/ F0 j5 l% v
  14.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ3 q8 f" S' g; `( k  n! ?
  15.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK
    8 Z) H9 Q: j* ^, s- |6 g) b

  16. 3 L, l1 \! E* O6 D: i
  17.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready  v1 U6 F! d& I! v6 p. p
  18.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock
    - J8 u1 S0 m1 p2 P
  19.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source" Z/ Z( W- {  w$ r! i) u- f
  20.         
    ) ]  G) ~. k& U" t$ P, ^( [0 L$ ~
  21.         //---------打开相应外设时钟--------------------4 f( ?9 G& l9 N  ^5 _9 G# ~) X( L
  22.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 
    . F6 [3 g9 j2 c) N2 m' {- `/ a
  23. }
复制代码

, B8 {" M, T2 O( [* K
, z( I5 H# Z3 D* ~# ?也就是我们时钟树框图从左到右的配置,! L: [8 _9 o) ]* N6 v4 K
+ E* N* x/ n! @
时钟监视系统(CSS)

" v: B9 h% C  M& d8 i4 A' p
4 Q" P- M: e9 a3 K! f DQ]~7X4M)}}){71[QL3H6(P.png 6 q( u; @+ x* G* A4 z
  m- k. Q& c! B9 j, ~4 a
STM32还提供了一个时钟监视系统(CSS),用于监视高速外部时钟(HSE)的工作状态。倘若HSE失效,会自动切换(高速内部时钟)HSI作为系统时钟的输入,保证系统的正常运行。  Q8 `* e; t1 T9 V
* w8 S, Z5 Q1 h" w

: b$ _  N# P+ z# O6 z
赞 收藏 评论0 发布时间:2022-3-24 23:43

举报

0个回答

所属标签

相似技术帖

官网相关资源

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