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

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

[复制链接]
STMCU-管管 发布时间:2020-9-16 12:46
1 什么是时钟
- r$ ~. C( [# O: c. ]/ M
, c. f+ {! t2 d( x: E8 M

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

# z, N+ |: b# M$ L5 m

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

6 ?7 O9 `' F- {

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

+ f* F  J6 D, _: F* }
总括:
  • STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。
  • 系统时钟,是处理器运行时间基准(每一条机器指令一个时钟周期)
  • 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。
  • 一个单片机内提供多个不同的系统时钟,可以适应更多的应用场合。
  • 不同的功能模块会有不同的时钟上限,因此提供不同的时钟,也能在一个单片机内放置更多的功能模块。$ `" u) B) J/ i! q7 `, S, t
    对不同模块的时钟增加开启和关闭功能,可以降低单片机的功耗
  • STM32为了低功耗,他将所有的外设时钟都设置为disable(不使能),用到什么外设,只要打开对应外设的时钟就可以, 其他的没用到的可以还是disable(不使能),这样耗能就会减少。  这就是为什么不管你配置什么功能都需要先打开对应的时钟的原因
    , f$ J$ ~4 t4 P3 E6 K( Q

/ i0 j& q! e9 W: l- _" KSTM32的时钟系统框图

4 ?  ?# ~$ i3 G$ E0 v* H; K- `! ~
& {2 m6 L, h8 D& m1 X) G- @

20200916123825.0998637ab72eacb27e00679449ebf5b3.png


/ W# G( l0 e- P) b" y% k* K* A6 o, l6 ?  a  D$ X) m& W

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

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


5 j( S! \! Q& C0 G  y

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

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

STM32 有4个独立时钟源:HSI、HSE、LSI、LSE。
9 X0 [$ F1 a. c①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。
4 O8 q1 O3 {! X0 f/ c7 [1 a②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。3 y8 A9 c: D2 U
③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 
1 G9 `6 ]( x& ?$ Z0 ?④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。

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

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


/ t4 P& A0 s4 R. h

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


. O% n1 n7 f" u% ~2 [( h

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

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

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


1 s" F' g) H4 ]7 I2 系统时钟SYSCLK
$ W2 S  v; Z# |
1 U! N1 y, ]8 k. V- c4 u

系统时钟SYSCLK可来源于三个时钟源:) a6 x& `' u, P/ S; q, n
①、HSI振荡器时钟' o8 Y4 o. {7 \  s! b% K
②、HSE振荡器时钟
* w/ e+ T* H3 r, q8 O* G③、PLL时钟
$ M  p2 Z3 E# w1 t' r最大为72Mhz

20200916123849.0391cd04e8b6be520c4bf1c3ad8984df.png

  U  ?. V0 Q% h7 J4 J

4 N% j6 G3 m3 K3 USB时钟

20200916123902.d7bfeac174ac9960e988c82caa879e43.png

- M3 K+ \) s( j0 [/ A7 B

- {4 l5 K$ u  b- G7 u* L

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

3 |; {; x, {* K# P

20200916123911.db07ceb8a00d8e00ac80dd7503668382.png


* b% ^6 w0 }3 e1 G/ w4 把时钟信号输出到外部

5 T! X3 C+ U+ _
6 ]7 z8 Z7 M4 l) e1 H- G1 ?( c6 {& s" S9 r5 {) ~' y7 F, [

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


5 c0 x" z; ~7 J& m9 N5 S5 系统时钟通过AHB分频器给外设提供时钟(右边的部分)  重点

2 _% I1 x, j1 [2 f/ ^; t" t! Q& A4 X" Q7 k3 `, w! Y

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

3 \2 x* Q6 n9 x# v8 G7 @

右边部分为:系统时钟SYSCLK通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给5大模块使用: & F" Q# l8 {6 z9 b+ v! i
- K2 _( C& p9 h: r6 I& ^4 V! Y
 ①内核总线:送给AHB总线、内核、内存和DMA使用的HCLK时钟。
! \  |" G' S7 @6 V' X# z* {8 s
: ?3 E. y- e+ `: _8 c ②Tick定时器:通过8分频后送给Cortex的系统定时器时钟。
. ]& w$ y( Z0 T5 d/ K% P8 b. |; W6 z( i& p" K+ f5 l9 a- X/ L9 W  |1 t
 ③I2S总线:直接送给Cortex的空闲运行时钟FCLK。 ' _( ?, @! ?6 I6 Z8 @

/ O6 W; x* N( ]5 u9 i2 F, K; D) N ④APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用。 6 q9 y7 |' E5 P/ \
( ]" P* G* ]2 P! H3 }4 ?
 ⑤APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。

* t7 x1 V" O9 `- L& V, W

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


% u$ y* Q. w# x6 N) g3 n( O! M) v7 e6 S: m

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


$ d9 ^6 G& q5 F, i, `APB1和APB2的对应外设F1系列
# V! a4 x2 J( Q9 _) f4 C8 |
* t. H8 A2 `4 _: K

20200916123921.cf81acbd84edb5c3195916f4ce2b1d8e.png

) b% N5 ?! ^) T  m8 x/ F  r1 [4 n

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

4 P( w8 O* y! ]$ b: n+ Z2 }

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

: p) V  e+ y* m/ o  ?3 {8 Y$ J' @
F4系列

20200916123931.42448b59fd29148eb0625908cf4664f8.png

6 g/ O( ^2 e' ?) n

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


. ^9 z4 ~4 g! Z( U+ A% ]+ s2 p

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

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

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


0 [5 a/ p9 k. E/ t  K, L) u

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

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


, u% J1 t# {. }% x2 DRCC相关寄存器:

$ H* H6 C0 p+ R7 q1 j3 N
$ \: x$ H, _7 d9 S

这里我们以F1系列为例


. ]+ u" _3 N5 {. R+ M+ Q4 W6 Y6 |* M: q& H

  1. 1 ^0 c, C# j' B; x
  2. RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下:
    ' ^* u5 ~) q9 k1 ]4 z

  3. ' r) Z9 T( p; a; L# ~  {8 Q
  4. 1059行->1081行。:  
    / m7 u) p  I4 m1 f- y2 g
  5. typedef struct  - `1 Y0 j$ N* Z3 X' ]& R, S# Z
  6. {  6 h" l. s  X0 N
  7. vu32 CR;                  //HSI,HSE,CSS,PLL等的使能  / c4 k6 Y# |. Q, P
  8. vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定 % ]0 ~7 X0 f# W8 }& h: u: e" a& U; M
  9. vu32 CIR;                // 清除/使能 时钟就绪中断 $ Z9 w/ i" R! N, q) ^) a
  10. vu32 APB2RSTR;      //APB2线上外设复位寄存器
    2 U9 y3 P: t7 o4 g4 T
  11. vu32 APB1RSTR;      //APB1线上外设复位寄存器 / A2 q6 `! H: ]$ _& b4 X0 t
  12. vu32 AHBENR;         //DMA,SDIO等时钟使能 ; R6 W! d& J! i, I) a# w
  13. vu32 APB2ENR;       //APB2线上外设时钟使能 7 v; O, U4 Y: j
  14. vu32 APB1ENR;      //APB1线上外设时钟使能
    # C4 b8 R5 N) e9 d. Q  h
  15. vu32 BDCR;           //备份域控制寄存器
    6 [8 k' E( f3 W- C
  16. vu32 CSR;             5 w4 ~4 H' {& f" z
  17. } RCC_TypeDef;
复制代码
" N9 Y5 I& t$ `9 ~, I7 A8 K
. ?1 V' ~) C0 m3 o- v7 x
" i7 Y, c$ R2 M

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


" u% U) o( v% e2 D9 Y2 T7 a6 Q9 s# nRCC初始化:

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

0 \) Z8 S& s: f# v& E& K4 R

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

. K7 W+ e/ A$ P7 Q4 K: [# _% x7 e9 s0 ?
1、将RCC寄存器重新设置为默认值   RCC_DeInit;
, I; y) h6 F- [7 B2、打开外部高速时钟晶振HSE       RCC_HSEConfig(RCC_HSE_ON);
4 |* E# _/ K6 o# s% O; F( i4 w3、等待外部高速时钟晶振工作      HSEStartUpStatus = RCC_WaitForHSEStartUp();) L8 w3 R! O; Q
4、设置AHB时钟         RCC_HCLKConfig;
" c  L9 W. L9 D) V; |; i6 T5、设置高速AHB时钟     RCC_PCLK2Config;
6 S" P; M2 B$ z; V$ a, F. V9 @6、设置低速速AHB时钟   RCC_PCLK1Config;
7 M$ L* F8 v# g2 N2 a( n7、设置PLL              RCC_PLLConfig;
2 C0 x0 D" {1 E8、打开PLL              RCC_PLLCmd(ENABLE);
5 L, d+ ]  I! z* B6 ]2 r/ l* _9、等待PLL工作          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  P8 X0 J6 P2 M+ V6 f! u0 \; b10、设置系统时钟        RCC_SYSCLKConfig;
$ l* z! Z0 w; Z  m3 y; Y- C11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
! h2 G5 Y; Z2 v0 ?12、打开要使用的外设时钟      RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

代码实现:

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

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


5 l' I- W; r6 O. K' `/ Y1 _) v2 C
  1. 3 {8 Z$ a# u& V* _" @' F
  2. void RCC_Configuration(void)
    5 v: G* c9 R# G; |0 Q
  3. {6 k1 w$ n# v; E+ z( M# O! R( j( C. x& q
  4.         //----------使用外部RC晶振-----------% U" h. M1 V$ M/ M
  5.         RCC_DeInit();                        //初始化为缺省值7 I+ c9 M2 @2 e1 L( m3 z
  6.         RCC_HSEConfig(RCC_HSE_ON);        //使能外部的高速时钟 8 Q8 L! X0 K3 Q" |9 l
  7.         while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);        //等待外部高速时钟使能就绪
    + F9 \5 C  D- c4 k; D: K. R4 d
  8.         4 X' U, Z' d0 j* u) s
  9.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //Enable Prefetch Buffer
    ( f2 }6 T, y1 k
  10.         FLASH_SetLatency(FLASH_Latency_2);                //Flash 2 wait state
    $ K' I2 z+ P- |/ _7 G, P+ H
  11.         * x9 `, a2 }1 a2 m1 y$ u9 U
  12.         RCC_HCLKConfig(RCC_SYSCLK_Div1);                //HCLK = SYSCLK! o) H  R* j: L4 I* d+ c
  13.         RCC_PCLK2Config(RCC_HCLK_Div1);                        //PCLK2 =  HCLK
    ; u/ C. c) o- k) B3 X
  14.         RCC_PCLK1Config(RCC_HCLK_Div2);                        //PCLK1 = HCLK/2- ~, r; h! P) V5 h' s( S( Z
  15.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);        //PLLCLK = 8MHZ * 9 =72MHZ
    , J, d4 n. |6 y0 U3 ^1 ]
  16.         RCC_PLLCmd(ENABLE);                        //Enable PLLCLK
    * G3 H; A. }4 k) `* ]" ^

  17. ( b. a, e$ m: ~; W2 @
  18.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);        //Wait till PLLCLK is ready- V- P9 L1 |. }$ `# L
  19.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //Select PLL as system clock7 B) |. F* {- H
  20.         while(RCC_GetSYSCLKSource()!=0x08);                //Wait till PLL is used as system clock source% G% \; Z* d/ G( g4 J
  21.         
    7 c% t" R' b& k( g; l
  22.         //---------打开相应外设时钟--------------------9 H% y: Y0 {8 q* f- ]4 h3 M
  23.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能APB2外设的GPIOA的时钟                 & w! b0 e9 M7 `7 z. X2 _
  24. }
复制代码
& A) e5 o* z9 |/ x  V5 Y* A

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

时钟监视系统(CSS)

: o' G: A$ m  _; c7 T# J0 E: Z4 F% ]/ V$ V* H# d

20200916123946.27093bb492c0b8a5c4b8d221c9115162.png


) ^: e# i' z' ~) h% H4 J

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

$ {. K2 u5 c  w6 U8 A# f

7 o" E! ~3 I$ f5 i
3 `/ j) H. m8 }& k; n6 T8 C* R$ C5 R) l
赞 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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版