请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU-管管 发布时间:2020-9-16 12:46
1 什么是时钟) H# D/ }6 F/ L) x. I7 }

, K: Z- _; D* @* A0 h& X; |

时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。


/ d$ X: s) e3 f  L! N. G

为什么 STM32 要有多个时钟源呢?

$ J$ m: Y/ b- b8 s

STM32本身十分复杂,外设非常多  但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费   并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树

$ M& j! K1 g; S1 D+ u
总括:
  • STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。
  • 系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)
  • 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。
  • 一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。
  • 不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。
    3 e  w; _# D: N% d* U/ e6 Y对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗
  • STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因
    4 Y. L4 i2 {1 c; g' a7 B
; c( k$ {' N; A4 q9 a
STM32的时钟系统框图

# @4 ~( M9 P+ T$ R) S% O/ s
: K$ M/ w& g* |  ]# W9 j

20200916123825.0998637ab72eacb27e00679449ebf5b3.png

2 b/ a8 l1 ~8 R3 F; o7 Q
  W& V# {/ ~; R7 Y0 d% p. _  I

乍一看很吓人,但其实很好理解,我们看系统时钟SYSCLK 的左边  系统时钟有很多种选择,而左边的部分就是设置系统时钟使用那个时钟源,   

系统时钟SYSCLK 的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率

  v/ o! o5 C2 B; d. P( z

从左到右可以简单理解为  各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置

时钟系统1各个时钟源    (左边的部分)

STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。6 p; [/ |5 @7 k" a
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。% P. e+ T' I( N6 v1 L7 h
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
* ~/ g( c0 ?( w; D( R③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。  4 R) e) }/ M: o( C  ]
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。

其中LSI是作为IWDGCLK(独立看门狗)时钟源和RTC时钟源 而独立使用

而HSI高速内部时钟 HSE高速外部时钟 PLL锁相环时钟  这三个经过分频或者倍频 作为系统时钟来使用

) Z! c+ D& n' \2 a! F. n: _

PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。  通过倍频之后作为系统时钟的时钟源


! A8 [2 q- H" A: b* X! j. I) _

举个例子:Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。

或者内部RC振荡器(HSI) 为8MHz  /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz

PS:  网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟

6 h% ~6 K/ x8 u
2 系统时钟SYSCLK
. ^3 C! r: {! m$ N
/ c5 Z, ~* o! g% h+ M  z

系统时钟SYSCLK可来源于三个时钟源:2 \+ T% ^& v% l6 T3 _
①、HSI振荡器时钟
& g7 [, W! M  \②、HSE振荡器时钟+ h9 N7 o, E1 P- ?2 }
③、PLL时钟3 D3 a4 \. m0 x: I- @) ^
最大为72Mhz

20200916123849.0391cd04e8b6be520c4bf1c3ad8984df.png

. e, B$ Z  u- Q/ l4 w

& }5 u1 d' @8 w1 n3 USB时钟

20200916123902.d7bfeac174ac9960e988c82caa879e43.png


6 N& X1 K7 V+ A3 q3 t$ d  ?& s

+ S0 L, q8 p9 e: w" v

STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz

( Z% ?3 O# t6 _' w2 b

20200916123911.db07ceb8a00d8e00ac80dd7503668382.png


: H" g* x& Y' m$ P/ |4 把时钟信号输出到外部
1 Q9 W5 D+ I. M- p( q; `
  h0 `$ h7 }5 ~* w2 d
/ Z, ]+ }: V/ ?

STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用

9 r; s5 B4 w4 V/ T- r. |! G
5 系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点

9 {7 _6 F! q# D+ r2 U. H* N; T$ V/ V

从左到右可以简单理解为  系统时钟--->AHB分频器--->各个外设分频倍频器 --->   外设时钟的设置

0 V' n$ g7 q3 x5 T+ ~; Q# O

右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用:
4 }" _' Q9 f' u* _- O4 C, f8 K/ y0 [9 t9 s  @* v% g
 ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。 ! l; [! u% Q1 w2 b8 k" N
6 A1 R4 A: v$ H5 N! H
 ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。
3 m: w! C5 ?2 Z1 I4 l0 \- R7 f# K1 d, U/ N% `
 ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。
6 |2 ~" Z7 X, q+ }7 ^
; T# U( Q8 k; }$ r; n! ^. W1 F) } ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。 + V6 L2 A) F5 M9 x* ~$ q

6 t6 z- \; V! F7 o5 @9 @ ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。

3 c. g2 w& Y/ v. l/ _- ?

另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。


  I7 M# U5 y+ _4 S0 k( P6 Y  f

需要注意的是,如果 APB 预分频器分频系数是 1,则定时器时钟频率 (TIMxCLK) 为 PCLKx。否则,定      时器时钟频率将为 APB 域的频率的两倍:TIMxCLK = 2xPCLKx。


% _# ^  E0 o1 B3 k. D" nAPB1和APB2的对应外设F1系列
: ]2 g! }  c5 _* X
% y, Y3 a" X; a8 G! m

20200916123921.cf81acbd84edb5c3195916f4ce2b1d8e.png


/ W: S# w* S2 }2 ?; ?1 O

APB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;

: _3 V. U+ `$ b$ l# J

而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。

3 M6 n' Y* ^. @6 w( q# o$ K
F4系列

20200916123931.42448b59fd29148eb0625908cf4664f8.png


+ w% {& K# }* }( \' E. c

这个和F1系列类似,我们就举几个特殊的


0 i5 a9 C" I8 D8 e

APB2总线:高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11   UTART1,USART6

APB1总线:通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7  UTART2~UTART5

F4系列的系统时钟频率最高能到168M

5 O7 o/ G0 o  p6 N9 W: B+ g2 q, l

具体  可以在 stm32f10x_rcc.h  和stm32f40x_rcc.h   中查看

或者通过 STM32参考手册搜索“系统架构”或者“系统结构”  查看外设挂在哪个时钟下,

' P/ u2 }: ~6 W
RCC相关寄存器:
! e* d6 B/ x" u" G! D; A/ |

' s6 E6 b4 |) `9 ^- q

这里我们以F1系列为例


( U( I+ k8 j3 n, I7 h7 ]

  1. ; L+ z" H1 T; `+ `# s2 F
  2. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:
    + B8 I) p" v# b' O

  3. & z8 h  K3 j/ K- m
  4. 1059行->1081行。:  
    1 o) D% m0 Z" ^
  5. typedef struct  
    , j  C5 I, V) ^( w. v3 k
  6. {  
    . z/ O* H3 w* C  Z! _2 n' q; `. n
  7. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  $ \" r' A6 N- _& U
  8. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定 ) l5 W& l! q% J! n/ Z7 E5 W
  9. vu32 CIR;                // 清除/使能 时钟就绪中断 9 r1 l; f9 E) S# A3 i0 T6 b
  10. vu32 APB2RSTR;      //APB2线上外设复位寄存器
    # K: [9 f9 r& b+ }8 p
  11. vu32 APB1RSTR;      //APB1线上外设复位寄存器
    2 o* v$ D) _3 P0 J+ P% v
  12. vu32 AHBENR;         //DMA,SDIO等时钟使能 ! v6 O0 G, S9 t. m) m& U
  13. vu32 APB2ENR;       //APB2线上外设时钟使能 # y* N/ y# }* f/ i$ t; ?" A
  14. vu32 APB1ENR;      //APB1线上外设时钟使能 1 z) ^( ~" \$ ?1 L% ]$ }
  15. vu32 BDCR;           //备份域控制寄存器 % L+ q0 A8 E) d) \9 _
  16. vu32 CSR;            
    # ]7 A7 i# j* `3 ?, n$ t  J
  17. } RCC_TypeDef;
复制代码

& n% H' s; b! s; k
2 o' L# T/ s  G1 C/ r: q- U+ ?  }2 d

可以对上上面的时钟框图和RCC寄存器来学习,对STM32的时钟系统有个大概的了解   其实也就是我们上面介绍的流程,理解了自然也就能写出来

/ @8 x1 _( K8 v- V! s. c
RCC初始化:

这里我们使用HSE(外部时钟),正常使用的时候也都是使用外部时钟


6 J2 J8 E9 K8 n. u  g

使用HSE时钟,程序设置时钟参数流程:

3 t2 ^8 G, N8 a& l, j
1、将RCC寄存器重新设置为默认值   RCC_DeInit;
" \& Q% ^: r' T5 v4 U# b; n% T1 t2、打开外部高速时钟晶振HSE       RCC_HSEConfig(RCC_HSE_ON);
5 _' m8 t5 K; V: a( Q" r( V3、等待外部高速时钟晶振工作      HSEStartUpStatus = RCC_WaitForHSEStartUp();
8 e5 i) S# w  a7 ^/ w6 \' v" Q4、设置AHB时钟         RCC_HCLKConfig;
+ ?% J4 ~# b7 }- q5、设置高速AHB时钟     RCC_PCLK2Config;+ [* [  A7 X8 q6 Q5 x! G) P2 L
6、设置低速速AHB时钟   RCC_PCLK1Config;
. G) I0 c" K$ R6 ~7、设置PLL              RCC_PLLConfig;
+ p$ B6 k5 I( {$ b- l# V6 H8、打开PLL              RCC_PLLCmd(ENABLE);8 I2 |3 Q& I$ }( |
9、等待PLL工作          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)8 ?) w# Z' d) g/ I3 ^  I1 X
10、设置系统时钟        RCC_SYSCLKConfig;& X- v! T# W% b0 z* ^2 |
11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
6 h% x7 v1 u# z12、打开要使用的外设时钟      RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

代码实现:

对RCC的配置函数(使用外部8MHz晶振)  

系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M

5 b: ^1 ~7 x9 T
  1. # ~, K1 _& D0 ~' v& {0 Z' P
  2. void RCC_Configuration(void)
    ( a6 K9 v. }) V+ v6 l! a2 L
  3. {
    1 t% g! z5 P: K0 ~$ y4 j1 ]" q
  4.         //----------使用外部RC晶振-----------
    * r' P9 ?# K8 ^7 s2 R
  5.         RCC_DeInit();                        //初始化为缺省值
    1 _3 R; |& w/ j
  6.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟 0 d2 }5 N% {7 o
  7.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪* Z$ a% c. a7 u7 M; P, a) w9 b
  8.         9 Q/ X0 y& P* O9 f4 f2 s
  9.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer
    8 D/ `% i; _: o$ T
  10.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state
    $ e1 B/ X) |  q; j" Y- z- }; t
  11.         
    - z9 k1 y, u, T0 `6 X! S9 u
  12.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK- S$ j  \( z2 F3 ^
  13.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK
      s4 y$ @- p3 J' |% ^. I
  14.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/2
    ' [% g/ _6 e+ Q$ ]1 [! v, \
  15.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ
    % k& c. r3 Q# ^  e8 B0 n
  16.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK
    $ D/ t# h+ C  B. O$ \1 \: R7 z1 P/ _
  17. 2 R( T# p" y# N& v9 `) A; m' S
  18.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready3 J9 F6 J# Y2 e% Q/ h" q5 l
  19.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock
    ! E$ @. t$ k! ?7 Y) `5 T7 Y8 C
  20.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source+ Q0 [- w! Y, A5 T5 Y
  21.         * R/ s* |  a5 L  V
  22.         //---------打开相应外设时钟--------------------3 [, i7 z; l3 R) q0 ?5 k2 |
  23.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 8 p: C. e, G1 S% t" j
  24. }
复制代码
0 l3 t+ u- Q/ V2 a

也就是我们时钟树框图从左到右的配置,

时钟监视系统(CSS)

% B+ C4 _: S6 ^9 n6 Z5 f" h/ G$ C6 U8 E, }" j* V7 }0 K7 G

20200916123946.27093bb492c0b8a5c4b8d221c9115162.png

. `% j3 K2 r/ O. r4 W3 R/ O0 I

STM32还提供了一个时钟监视系统(CSS),用于监视高速外部时钟(HSE)的工作状态。倘若HSE失效,会自动切换(高速内部时钟)HSI作为系统时钟的输入,保证系统的正常运行。


3 \! Q4 {: y9 T: T# }
7 g+ a8 A7 V0 g8 S- X

5 N+ U2 X# r3 X" m
# o4 G1 k6 x+ Y! P) `
1 收藏 1 评论3 发布时间:2020-9-16 12:46

举报

3个回答
久远寺有珠 回答时间:2020-9-16 18:04:08
提示: 作者被禁止或删除 内容自动屏蔽
AG5JZ 回答时间:2020-9-17 08:13:12
学习了,谢谢分享!
左岸右岸 回答时间:2020-9-17 09:56:30
介绍得很清楚!

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版