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

【经验分享】STM32- 时钟树、时钟配置

[复制链接]
STMCU小助手 发布时间:2022-1-28 20:57
reset clock control 复位和时钟控制器
一、stm32时钟树
( D1 ^5 y' r5 c& u9 M: f: b' K5 y- S
1251897-20190520122927631-2146778766.png 9 R0 |3 i' }: b3 R, P1 l$ E4 D, v
$ F2 e6 v, W( M- l
stm32时钟树:由时钟源到外设的结构框图。
基本时钟源(图中绿色箭头指出):
(1)HSI高速内部时钟,RC振荡器,8MHz。
(2)HSE高速外部时钟,石英/陶瓷谐振器,8MHz。
(3)LSI低速内部时钟,RC振荡器,40kHz。
(4)LSE低速外部时钟,RTC石英晶振,32.768kHz。
注:内部指的是片上外设,外部指的是芯片外部。
(5)除了上述基本时钟源,还有num3中的PLL锁相环倍频时钟源,它是将HSI和HSE倍频后输出。
二、PLLCLK  -  PLL时钟(num4)
时钟来源:(1)HSI/2        (2)HSE
三、SYSCLK  -  系统时钟(num5)
时钟来源:(1)HSI          (2)PLLCLK      (3)HSE
SYSCLK经过分频后,得到AHB总线时钟HCLK;
HCLK再分频得到APB1总线时钟PCLK1和APB2总线时钟PCLK2;
PCLK2分频后得到ADCCLK最大14MHz。
四、RTCCLK(灰色框中)
时钟来源:(1)HSE/128   (2)LSE             (3)LSI
五、系统时钟配置
系统时钟有三个来源,PLLCLK、HSE、HSI。
正常情况下,时钟配置是在system_stm32f10x.c中完成,这里的的时钟配置是直接控制寄存器完成的。
在 stm32f10x_rcc.c中定义了关于时钟配置的库函数,此时未用。
打开system_stm32f10x.c,找到void SystemInit (void),再找到 SetSysClock()并查看定义,
定义中可知是通过在system_stm32f10x.c中宏定义SYSCLK_FREQ_72MHz选择系统时钟配置函数SetSysClockTo72(),
即72MHz的系统时钟就是在此函数中配置的,函数如下:(HSE(不分频)->PLLCLK(9倍频)->72MHz系统时钟)
  1. static void SetSysClockTo72(void)
    ( ?1 U0 o- s3 f" ]' I) _
  2. {
    ( F1 M3 H, [+ k% D' s' ~
  3.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;7 D5 r  b6 b5 T
  4. & N2 z: p% C9 U! \
  5.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
    & B% t6 ^8 o& g+ }3 u
  6.   /* 使能 HSE */9 D3 w7 S8 `* n+ h0 M$ t
  7.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    ! L) r, `# Z- g1 j. R9 Z

  8. ; a+ B0 X6 Y' c& g9 w4 D% P
  9.   /* 等待HSE就绪并做超时处理 */* Q: N: O; m, ~% k
  10.   do
    2 l: k$ g7 a# w& m# U
  11.   {2 s5 g$ s. _( _- ?8 {  q
  12.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    5 H4 d! }9 h) G
  13.     StartUpCounter++;
    - P- ~3 g1 D7 N0 @
  14.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));9 z3 x& O0 |8 v' P

  15. 8 _# o/ J* y8 v* J
  16.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)* R6 `9 T# R/ D6 Y
  17.   {
    4 ?7 W. T5 [9 b
  18.     HSEStatus = (uint32_t)0x01;
    $ b4 z' R9 i& R# f- P- E
  19.   }
    , v# B# q( o- y* {
  20.   else# X0 N' F) {+ K; @! i# v' b
  21.   {  `: H( k( b; D8 |, M6 x
  22.     HSEStatus = (uint32_t)0x00;3 c) @* e1 j8 ~7 r% R2 ?
  23.   }
    8 ^) ]% r- ^+ m
  24. : y2 |$ h: B% ]# G5 v# L
  25.   // 如果HSE启动成功,程序则继续往下执行
    # q5 b) z! n9 i7 D& b+ s
  26.   if (HSEStatus == (uint32_t)0x01)
    # B7 G7 W( v. x8 N' Y
  27.   {1 Y0 E: J3 x. D  \
  28.     /* 使能预取指 */, _0 K- N0 D1 M$ B" S
  29.     FLASH->ACR |= FLASH_ACR_PRFTBE;  _- q8 e' p* ~5 w
  30. ) q" E  y( Z% ?
  31.     /* Flash 2 wait state */  o) l7 H7 F2 I8 `! n( j
  32.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    $ `$ t  B3 Q' h1 b9 J& z$ q- Q
  33.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;6 ~3 ~0 J& }/ n

  34. ) C! {% y4 q4 M7 Y" p

  35. 8 E1 V9 `" _" s& I* [
  36.     /* HCLK = SYSCLK = 72M */( L. ^' Q9 x2 u& ]. b& @
  37.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;1 R( ?/ z7 |1 V- ?  S) R& B  c4 h
  38. + ]6 c/ V8 e$ }9 i
  39.     /* PCLK2 = HCLK = 72M */9 {3 o1 \$ ]. K8 d5 O% B4 h
  40.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;: U/ g; B" B( b

  41. # T  |% ]& L) U4 L; u* I
  42.     /* PCLK1 = HCLK = 36M*/! C  M& V6 R+ ?; m4 V! T
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;& x5 I' l0 J5 W

  44.   x6 ]4 v% P4 r5 ~3 j0 M  \
  45.     /*  锁相环配置: PLLCLK = HSE * 9 = 72 MHz */( [7 o% s5 x, g  h1 l: {- c0 @4 ^
  46.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |$ n! _! P$ ]6 j, w
  47.                                         RCC_CFGR_PLLMULL));
    7 s& F0 `1 m6 z
  48.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
    : C/ j+ f  J' _' l  O" w: G& y, B
  49. ! G% u; h: m9 P! z- N2 N% G
  50.     /* 使能 PLL */: O; a* [2 O! n. V4 K/ f% `
  51.     RCC->CR |= RCC_CR_PLLON;
    3 J- Q, K: N2 l3 J* ]% d- c
  52. ! v. B2 a/ R$ L( m) o: @5 c
  53.     /* 等待PLL稳定 */
    ' m$ g2 y1 I3 g0 S8 M
  54.     while((RCC->CR & RCC_CR_PLLRDY) == 0)/ L' v' I3 W5 I; y8 E" f7 o
  55.     {
    ( K! C( ]2 ^7 a0 \8 F: X9 j# e
  56.     }; A, A8 a+ `; n/ ?' |7 \$ a
  57.     /* 选择PLLCLK作为系统时钟*/$ ?3 _4 }& V8 C7 i1 e# B0 B- D3 L
  58.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));  y% B* Y! s; G2 H5 O: f+ ], m" ~
  59.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
    5 B3 X4 x0 t3 ?8 b( u! |( h9 J" _

  60. 1 b0 [% B0 t( M7 F2 E( T
  61.     /* 等待PLLCLK切换为系统时钟 */
    " k) a+ u/ N" B
  62.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    8 r3 }$ V: m: C/ o0 K
  63.     {
    - O2 i% U* m- l7 R8 D; E
  64.     }
    " P% A# }$ [+ N! e6 c) b
  65.   }
    , a9 C" E& |: w
  66.   else# O/ e1 J+ U) V6 W
  67.   { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */5 L( c' w3 R, e( t# {, z
  68.   }- E& o0 K0 t2 w- P+ J- v; {1 i
  69. }
复制代码

$ G( }8 P, |6 ]3 o
这里再以库函数形式中重新配置系统时钟和MCO:
user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的)
bsp_rccclkconfig.h
  1. #ifndef __BSP_RCCCLKCONFIG_H4 F% f/ [& K" i& U  B8 M# M4 @* U4 q$ N
  2. #define __BSP_RCCCLKCONFIG_H
    - x6 B5 n! V3 u/ \9 [

  3. 3 |! s  l2 a% v( _$ L
  4. #include "stm32f10x.h"
    6 x0 V! M& g$ {% P4 Z8 U  [9 c( {  m
  5. : {0 K% a5 r! n/ B# e, w3 J
  6. void HSE_SetSysClk( uint32_t RCC_PLLMul_x );/ ?; E2 T: [) f4 A+ u/ o; r
  7. void MCO_GPIO_Config();$ G! F& j* M; u+ ?
  8. void HSI_SetSysClk( uint32_t RCC_PLLMul_x );& ^- K" L. j; V1 @7 Y& e- g5 \$ N
  9. #endif /*__BSP_RCCCLKCONFIG_H */
复制代码
bsp_rccclkconfig.c
  1. #include "bsp_rccclkconfig.h"
    ; |  d0 k( Y! l% A$ @
  2. # M% X. H* M% g
  3. void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
    2 U6 q' c2 E" B
  4. {5 f9 O; l& H5 H0 `! C2 F# \1 c
  5.     ErrorStatus HSEStatus;
    & }+ G" n- M* c  b

  6. . W3 A9 p( p- E3 P0 V! I$ _
  7.     //把RCC寄存器复位成复位值
    # `4 q# C  e, f; v' @- r: u
  8.     RCC_DeInit();) W( ^+ W. Y8 h

  9. " _% Q% @3 o& a  r5 h, w2 q
  10.     // 使能 HSE* Z/ A, G! q+ z! v
  11.     RCC_HSEConfig(RCC_HSE_ON);) Z- q- I3 ~, R# L. z

  12.   }4 x0 T0 {# G7 t: X) Y* y. E+ b
  13.     HSEStatus = RCC_WaitForHSEStartUp();
    2 C" G! H/ S/ j% o
  14. ) ]+ n! ?0 m' M
  15.     if( HSEStatus == SUCCESS ). l2 ^9 o+ Z) `) m0 h
  16.     {5 {* A9 J5 e2 c8 [/ h# ~
  17.         // 使能预取址$ c8 y" X  @& y
  18.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);- l( q- j+ @# T3 T( P
  19.         FLASH_SetLatency(FLASH_Latency_2);1 \& \# {! F, ]3 L

  20. 4 y3 `% f1 B( }6 M; {8 V/ p- b
  21.         RCC_HCLKConfig(RCC_SYSCLK_Div1);4 \3 t: J6 K7 @
  22.         RCC_PCLK1Config(RCC_HCLK_Div2);3 [" j: a2 y2 _+ P; \
  23.         RCC_PCLK2Config(RCC_HCLK_Div1);/ w7 w. [/ l& }! O
  24. 2 s6 A) ?3 z$ J6 A  f
  25.         // 配置 PLLCLK = HSE * RCC_PLLMul_x
    2 B. \. I5 j/ w8 u( U) W
  26.     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
    2 M7 f3 p+ w, q, s' E$ k! p7 f. m$ P
  27. / l1 }) s" I2 d" J. T% l8 |
  28.     // 使能PLL8 e8 w/ O6 a/ T; p* O
  29.         RCC_PLLCmd(ENABLE);  d+ J4 e4 {0 |  t3 y4 j. Z( d- t

  30. ) q" _! M  i$ ^4 I5 K
  31.         // 等待PLL稳定
      K8 i. U6 r9 Z0 ~/ o) x1 K
  32.         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );6 U" b$ s' G' G- a& D9 \

  33. 5 Q0 P1 ^3 Y8 z3 U
  34.     // 选择系统时钟# N6 ^- l7 `) f3 u0 |+ w
  35.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    6 [# G4 Y9 O+ Y% \7 G9 c

  36. 6 v/ I7 n5 U8 u  [/ M/ K1 a- v  m0 A
  37.     while( RCC_GetSYSCLKSource() != 0x08 );$ J& P( n, W% w" E5 b& V: R
  38.     }
    - f) t& }1 E. G! H
  39.     else$ ?# Q8 e! Q* u5 A; A' T
  40.   {
    1 y6 m- B* Y% D
  41.         /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */
    . i. I0 |: c% F: V8 U% Z; X" u( L, ~
  42.     }
    + y. `+ g) Z3 a0 x
  43. }
    . D, Q3 D* W) {: L4 Y! \- i
  44.   Q: ^5 F# y( u- K1 W
  45. void HSI_SetSysClk( uint32_t RCC_PLLMul_x )( H3 {6 K0 K  U5 ?; a( t# ?
  46. {4 B. F" a4 k+ L% A* ?% O
  47.     __IO uint32_t HSIStatus = 0;
    # @# a. U! o9 w! |* R; p& e& {
  48. 1 v% _" W1 f" K/ |
  49.     // 把RCC寄存器复位成复位值5 B) G/ P  z+ N  Y" J0 }% _  S
  50.     RCC_DeInit();
    ! B& Q. x% h9 Q, a
  51. 9 u* o/ c5 [  q
  52.     // 使能 HSI: j# M5 b- V) ^, ]! U: M# \
  53.     RCC_HSICmd(ENABLE);
    3 G- X- {" E8 R8 W8 u( ~/ Y
  54.   t: Y& j5 o4 \$ I
  55.     HSIStatus = RCC->CR & RCC_CR_HSIRDY;
    $ M" Y2 {5 h) D: N# {; i8 X

  56. 1 e8 F2 J4 I+ V! @3 m
  57.     if( HSIStatus == RCC_CR_HSIRDY )* W/ P' f; y; T. Y# x+ f$ I6 U* S
  58.     {- m5 f: C% I- q$ \  x% G' e
  59.         // 使能预取址
    : P- m' y) c# q! t
  60.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);7 O5 {" P4 u" B& r, h
  61.         FLASH_SetLatency(FLASH_Latency_2);. P: [' L6 }$ x$ U: q) r

  62. 3 p0 ^5 t8 ?1 c# B
  63.         RCC_HCLKConfig(RCC_SYSCLK_Div1);6 W$ V- S1 {1 V
  64.         RCC_PCLK1Config(RCC_HCLK_Div2);
    ; K- x" P. Z5 h4 M
  65.         RCC_PCLK2Config(RCC_HCLK_Div1);
    8 x$ c0 n+ t6 \) f0 }/ k
  66. * N& ~) |5 C! B3 E$ k
  67.         // 配置 PLLCLK = HSI * RCC_PLLMul_x
    1 g4 x+ }1 N# r' x
  68.     RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
    ' L6 J( c- W+ @; T2 _

  69. , R/ d, w. r) P9 V8 h
  70.     // 使能PLL5 Y/ |- Q- c. t& A; {5 h
  71.         RCC_PLLCmd(ENABLE);) L7 X! G4 p' w6 `' |8 u* K

  72. % z! k1 S9 U  [5 ^; s& P9 h  C
  73.         // 等待PLL稳定- p! L: Z+ @  J" a! h3 q
  74.         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
    7 `" R2 K8 v( A7 V# }; |8 k# t+ |
  75. 1 B3 Z( ?# c$ T* n
  76.     // 选择系统时钟
    ; {$ Q# m$ L) T; Z, x: Y
  77.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    6 L: _. A3 u# q& r1 R( I0 |
  78. 6 u! A, S2 f% ?0 O1 b5 Y- D' R
  79.     while( RCC_GetSYSCLKSource() != 0x08 );/ z/ \3 b( k6 E/ ^
  80.     }* F2 ~8 I0 ~9 [, g- h( S- A
  81.     else
    ; X! A& {0 P. a$ E$ m
  82.   {/ G1 q8 q: C/ G
  83.         /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */1 y3 S# E( \. [0 Y
  84.     }
    0 N0 Z, [, D* p. p6 g
  85. }2 N$ k& e! s5 W* c! k& n7 M+ Y6 Z

  86. / k: L# Z, `2 _
  87. void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8
    3 ?! V  I# n: B
  88. {& L/ Q& n9 o) Z# V: \
  89.     GPIO_InitTypeDef  GPIO_InitStruct;
    & ?5 x" u$ P# q+ i$ L0 C/ j6 V

  90. 3 \3 b# k7 x+ C1 [% i
  91.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    5 X/ J  r" i# q
  92. & A, b# }# O  I1 ~
  93.     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
    ; U* r; g7 F6 b% T5 N
  94.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    3 {  ?- g1 A" o/ e6 L( _6 p1 Z
  95.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    # X" r" u# A! w; S' W7 V' U9 K

  96. 4 r0 C1 }; L. w+ }! p# B. o
  97.     GPIO_Init(GPIOA, &GPIO_InitStruct);4 h# l  T3 p8 H; t- \7 r" |
  98. }
复制代码
1 |( b" B/ k' u2 f9 F
main.c
  1. 1 #include "stm32f10x.h"   //
    . T. D, K; U- }" q* M+ Z2 A
  2. 2 #include "bsp_key.h"
    * `$ x: c" E& e
  3. 3 #include "bsp_led.h"
    7 b+ @) c" U! Y" u
  4. 4 #include "bsp_rccclkconfig.h"
    % L  M& ^( Z! `& T5 U
  5. 5 void Delay( uint32_t count )   //软件延时函数,但是实际时间间隔取决于系统时钟
    # c2 }/ O- E+ O; H
  6. 6 {* }5 t  m5 C+ z) n2 l
  7. 7     for(; count!=0; count--);
    $ R6 p2 p0 Q6 o! t) l3 }
  8. 8 }7 o4 W% O9 r5 ?- e$ z4 |
  9. 9
    3 N* t+ Z* @# r6 f  h& D4 Y& f
  10. 10 int main(void)4 h7 U, y" a, f& S# q1 z
  11. 11 {
    ; P, X; j& Q( c6 B. q
  12. 12     // 来到这里的时候,系统时钟已经被配置成72M1 ~7 T  x5 ]6 w" [- V5 q% D8 H
  13. 13     LED_GPIO_Config();
    / \8 i; k0 `) M; _! F
  14. 14     KEY_GPIO_Config();
    " h# ~& }. K( U5 @9 j' S3 }" y
  15. 15     //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M16                                    //HSE=8MHZ,PLL九倍频=72MHZ" _3 \( T8 n2 l' I: r
  16. 17     HSE_SetSysClk( RCC_PLLMul_9 );5 H7 l2 A2 |. _; p" k
  17. 18                                    //HSI/2=4MHZ,PLL十六倍频=64MHZ0 e0 o$ F' N" h6 H' {3 d
  18. 19     //HSI_SetSysClk( RCC_PLLMul_16 );! F2 I. o8 X) A2 i  Q) v5 q- X; g
  19. 20     
    9 V* U9 ?& `0 H
  20. 21     //MCO的GPIO初始化# d% g8 n5 i4 V) _4 |
  21. 22     MCO_GPIO_Config();
    * z  _4 I. D6 v: Z8 c' @
  22. 23     //选择系统时钟作为MCO输出
    2 i0 e- G& H: t; h$ Y* o9 D; w
  23. 24     RCC_MCOConfig(RCC_MCO_SYSCLK);  //PA8接示波器可见7 \; u" a* x0 a8 \3 @8 }
  24. 25     //RCC_MCOConfig(RCC_MCO_HSI);
    / d; f& H4 f0 J/ f; Y
  25. 26     
    9 H: C" w2 f( t( E
  26. 27     while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化
    / O6 y4 [$ R$ O. t: O# x
  27. 28     {
    : s- t& D% G' x1 L5 H; z! U- a
  28. 29         //* X' ]8 T7 K" V8 I
  29. 30         //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON )
    1 n0 Q. f1 u4 R! d& Q& O; @
  30. 31         //    LED_G_TOGGLE;4 t9 @1 E$ w" A4 g
  31. 32         # U, E1 ]0 `! @, A2 t4 H
  32. 33         LED_G(OFF);
    / [6 x5 w& H% H
  33. 34         Delay(0xFFFFF);' ]/ g( X( B/ X2 O4 h9 o( f) w
  34. 35         . [" q0 J7 ?' a" q1 o
  35. 36         LED_G(ON);- C, c! l! B  ?0 p
  36. 37         Delay(0xFFFFF);
    ) M( Z3 W) j: y" \# F& ?
  37. 38     }
    5 l8 p4 J) x4 x2 q# Z0 ^
  38. 39 }
复制代码

( o* W( {7 S% {+ E
收藏 评论0 发布时间:2022-1-28 20:57

举报

0个回答

所属标签

相似分享

官网相关资源

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