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

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

[复制链接]
STMCU-管管 发布时间:2020-9-16 12:46
1 什么是时钟
5 v+ ^, g8 \+ H' F3 h3 Z5 I. ~+ ]& U6 F8 _) W. H

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


% [1 u2 f7 C& o6 {6 J, K1 |  P7 M

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

1 E5 Z$ W9 \) W; |; g8 ]

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


' y7 p9 J( F8 V0 z) T' g& n: m1 e总括:
  • STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。
  • 系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)
  • 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。
  • 一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。
  • 不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。$ Y5 c* [5 p! S$ l4 k
    对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗
  • STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因
    # {4 Y) S! V6 ^9 |* A  L4 ]

; ?3 G( ^0 F' f8 m- sSTM32的时钟系统框图

- ]7 U* z% \' M8 ~1 I3 R  d% p
; J6 [# |/ B4 Z7 h5 y

20200916123825.0998637ab72eacb27e00679449ebf5b3.png


8 }' \; |3 Z& g5 {) Q, L' E8 o, F, a7 W' _; `  J- ?: F0 M7 h2 d

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

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

. `" r& F: V6 V" L* L& G; x

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

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

STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。8 l6 @# a# e4 @9 d! |
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。5 a, V# ]2 `2 `2 q. }2 k
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
4 V1 |. o  I  N( `! Q1 r8 }③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。  % O! K# @2 e9 ]* m5 X/ W
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。

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

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


/ F, U( u$ a; U4 ]

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


# N8 C! p+ `* U

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

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

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


$ p. C# e1 @+ |2 R3 p2 系统时钟SYSCLK

) p& Y- D8 X" W9 D4 Y+ R7 X
* C4 p) I2 W8 d- ?

系统时钟SYSCLK可来源于三个时钟源:$ z8 ~" k! Y! s& |4 [0 r
①、HSI振荡器时钟( e  n2 m! J! B0 U* @" i3 w
②、HSE振荡器时钟, H" W# B' w1 `# @3 @
③、PLL时钟9 J3 @0 w7 X- T" U3 I2 a
最大为72Mhz

20200916123849.0391cd04e8b6be520c4bf1c3ad8984df.png


, q; k" r; ~% ]5 l7 o% H0 C* t: q  o' R2 |' g1 z. O
3 USB时钟

20200916123902.d7bfeac174ac9960e988c82caa879e43.png

2 A& M1 G% f: i  T


# @$ D$ X- O2 G4 o9 {0 A  ?

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


- p/ S) D2 ]2 u

20200916123911.db07ceb8a00d8e00ac80dd7503668382.png

, ?5 ?. s, q, Q  U* o* K; j
4 把时钟信号输出到外部

" k& `; w$ R) q7 k
3 [8 ^+ o7 S* u5 Q3 |  H% a/ n) ^' V# u, U

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

$ ?4 k0 y7 B) [& S
5 系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点

3 d" ?9 [/ ^5 v7 U# f$ @+ U
4 A0 @4 _0 X6 X/ J# ?

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

6 M) E  _0 O% L# F

右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用:
# s* R$ }- |* V+ e* m+ R# w' Q* T5 l
8 z) p" Q5 \- P% S- J/ s ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。 ! N. `7 P1 D" [% z! l

$ k) T" x7 U; g. @. H( V5 K ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。 3 Z* W5 f! |, g* G, r- Y# ~
6 ?7 r0 ]/ m) l) c( K+ O$ j
 ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。
" T6 U/ \7 i/ t, c0 T4 X$ O2 X/ U* n% n2 J; h
 ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。 $ d$ [: J8 c9 j* u9 t! f

% `, I( P. Y8 v0 i" L ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。


) R- s4 ?* q0 U8 q

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


$ n1 W/ R; E3 ^: M1 E

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


( e3 z' d6 u3 u  c) P' yAPB1和APB2的对应外设F1系列

1 V% z5 b% G+ r1 _$ q
5 ?: K1 `! b* m1 |5 S7 B

20200916123921.cf81acbd84edb5c3195916f4ce2b1d8e.png


/ H" s9 l* V1 a

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

5 `. T5 w1 ]3 D% v+ T/ [1 K( _

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

( [) |# m: N4 o4 N4 N
F4系列

20200916123931.42448b59fd29148eb0625908cf4664f8.png

7 w' A! I5 u) U5 u& D

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


3 J5 ?( K9 W& R1 j0 q* b5 g

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

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

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

5 X! ^5 t3 }, V( K/ t- I; B, |

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

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

, }) b0 q7 a4 D$ `
RCC相关寄存器:
2 K7 [2 l' Z- w/ t9 K, M( n, D
2 ]! b2 w: p4 N: `3 O7 L4 o) L

这里我们以F1系列为例

0 h; `, F# d6 f% @# \# D4 F& F
  1. : G2 T) q) b+ j. i( H- c7 _* g2 m
  2. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:
    , ]  i) E/ g4 q1 z; ]0 ]& b

  3. ( [3 ?8 A0 r4 P& z4 Y& s& W
  4. 1059行->1081行。:  
    ; x6 q& M$ R1 \# h# Z3 j, m1 b% C  v
  5. typedef struct  ; t( ?! @% ^9 X1 z  [5 Q# x
  6. {  
    7 |  i9 g" j& X* X1 d# W
  7. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  
    ) [8 K8 P6 O- O5 U' d0 K) n2 L( D. h
  8. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定 9 Q( Y: x' w: |* p9 y* ]7 P
  9. vu32 CIR;                // 清除/使能 时钟就绪中断
    " _) i" t9 n0 M# ~& G7 N8 i
  10. vu32 APB2RSTR;      //APB2线上外设复位寄存器 ! ^3 ^+ z9 S% i0 Q0 E/ H, u% Z2 {
  11. vu32 APB1RSTR;      //APB1线上外设复位寄存器
    + i! V$ b1 S  a; }; Z* h" E
  12. vu32 AHBENR;         //DMA,SDIO等时钟使能 . i7 w  T0 Z5 P
  13. vu32 APB2ENR;       //APB2线上外设时钟使能 8 a8 A( O- V1 B& Z
  14. vu32 APB1ENR;      //APB1线上外设时钟使能 $ O* J# M" t, [, T1 q. C2 m( ~
  15. vu32 BDCR;           //备份域控制寄存器 : Y2 [. P6 B' A6 n; a: V! \
  16. vu32 CSR;            
    3 v& q& J( t. M5 }9 q( O, D
  17. } RCC_TypeDef;
复制代码
- t9 G# I, a& l: R% ^7 y: [% Z

, A& V( T$ n& c7 O7 @* ]4 B% _% d, N

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


; k# ?/ C9 A1 p, T. h- v  S: LRCC初始化:

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

4 Q0 B0 ?* K% \* J: R

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

) g& H/ A, E* Y0 n. e
1、将RCC寄存器重新设置为默认值   RCC_DeInit;
) }9 c: l; C6 I! |. H2、打开外部高速时钟晶振HSE       RCC_HSEConfig(RCC_HSE_ON);
7 J) M0 Y  O6 A* q- A) u, P3、等待外部高速时钟晶振工作      HSEStartUpStatus = RCC_WaitForHSEStartUp();  v7 D8 M0 S+ E
4、设置AHB时钟         RCC_HCLKConfig;( |: M, F; }5 Y; _6 [
5、设置高速AHB时钟     RCC_PCLK2Config;; o( `# n0 ]' g$ [3 u1 M' B
6、设置低速速AHB时钟   RCC_PCLK1Config;
3 o2 V8 n# C. \: R6 u+ ?7、设置PLL              RCC_PLLConfig;9 V, m+ f" t5 Z# H+ ~$ {
8、打开PLL              RCC_PLLCmd(ENABLE);, x6 _- M" L3 m% M) A& o4 B
9、等待PLL工作          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)6 \1 J( U, m+ H4 m9 ^; X( E
10、设置系统时钟        RCC_SYSCLKConfig;0 t# c+ {: o6 @+ h
11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
/ @- k; Y( k5 w$ i( ^. M3 K12、打开要使用的外设时钟      RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

代码实现:

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

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

/ V, Y7 r) d  V+ V0 F& `# q
  1. ) x. y* A# V! y- F+ {& c. @! M
  2. void RCC_Configuration(void)3 ]2 k! I" k: R
  3. {- \! ^: Y. l# T
  4.         //----------使用外部RC晶振-----------2 v8 q$ }0 |6 x; r4 ?( x
  5.         RCC_DeInit();                        //初始化为缺省值3 C; p( V5 G) h' b) _) J' V
  6.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟
    4 ^, Q# F& i% M; D6 V2 u
  7.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪3 r3 _9 @, R4 b$ V" w( T( U8 P7 U
  8.         ( X, X3 U* W. ~: i
  9.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer. T! p5 X+ \* ?( B$ t
  10.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state; b$ `! S3 r- V! Y. m* u$ X
  11.         9 u- E( [; W( o+ i. f3 I# D3 g# ~
  12.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK* m  F: W5 R- a6 \9 p0 D& C
  13.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK9 |" x  z1 {" T5 Z" a
  14.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/2
    9 ~% w/ L% w' U0 C8 y) |
  15.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ/ V/ i8 R7 f% q
  16.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK7 M/ o6 ]2 [. a$ q. y

  17. 6 F2 n( T6 s. }, T) k
  18.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready' M# H5 [# Y- Y/ V9 J$ y
  19.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock
    ' j/ }4 T! C, e" H; Z# Z# u
  20.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source
    4 ^3 @' r: B5 h# }: L4 K; j* C0 B4 B
  21.         # x( y9 S. P# L" f
  22.         //---------打开相应外设时钟--------------------/ w) e7 h3 O) _  p. H
  23.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 
    * p1 f9 k+ k9 e) g/ }& ^
  24. }
复制代码
& J% f# T/ i% i

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

时钟监视系统(CSS)
$ M- m1 o( a" T3 m1 T
% J, d) o6 y6 @" ?6 ^' h9 y! y) O

20200916123946.27093bb492c0b8a5c4b8d221c9115162.png

0 {0 a% u3 r2 s" c% G* K

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

! V' @2 r* C- R4 b

# d! C# W, k1 A# Z) P3 \! U/ H$ W$ C' |5 G/ C9 o9 {& S

: G  D8 a4 A. x) a5 z
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 手机版