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

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

[复制链接]
STMCU小助手 发布时间:2022-1-28 20:57
reset clock control 复位和时钟控制器
一、stm32时钟树

- a9 I& w# }% w0 _  C 1251897-20190520122927631-2146778766.png
0 l% n2 B% b) Y7 A& k
& G, x- ~# D/ G8 j( }1 x3 V
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)
    $ w0 c' d, e2 K* h- u! d. {
  2. {
    ) {& ^$ \" x2 H1 j9 b4 L. S
  3.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;- D4 i: ]& J! v# s2 ^

  4. 8 G: I) i- ?- D. ^1 t! O9 H3 t% Z
  5.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/  K. k) r6 B& d% X( ]4 H5 ~
  6.   /* 使能 HSE */
    8 G. N; @- {% _, ]* t; F$ `
  7.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    5 \9 u7 B! c  u  w1 \; x$ [' k

  8. : J( h, J8 }( F- X+ G
  9.   /* 等待HSE就绪并做超时处理 */
    + J/ C* ]; e' L- M2 J# |' v9 ]
  10.   do
    / a- t, }+ \5 ]% H/ c
  11.   {
    ) s8 t/ g/ f; A1 U$ o  i5 ]) f
  12.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    ' Y% `; }7 k+ V% `5 K9 Y% }8 K
  13.     StartUpCounter++;8 E' k/ d2 A5 E  `0 h. _, u1 o
  14.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));6 m  ]4 h. R! f) X3 s! n( V  [
  15. . L" M5 k$ n  s: x- \, }
  16.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    % T: x" e* |! `% q6 r& N! D+ D
  17.   {
    9 Q9 d9 {  W& U- X% l# {$ _
  18.     HSEStatus = (uint32_t)0x01;8 V4 o+ ]8 _3 w' T
  19.   }& a/ K& F9 r/ E3 U9 F
  20.   else" g% F9 Q) b# ~. ]" ~5 a( w9 ], Y! G
  21.   {
    1 T3 C5 P( b, o1 c
  22.     HSEStatus = (uint32_t)0x00;& q7 H: W) G$ B8 m* D
  23.   }
    ; `) P, X, O/ }2 U6 Q

  24. 4 I  n2 _$ B( [% l- K1 d' a. J. b  w
  25.   // 如果HSE启动成功,程序则继续往下执行5 v$ A# I; R1 w) o8 S% s; m! h
  26.   if (HSEStatus == (uint32_t)0x01)5 V  J  @& \) {8 ^6 d9 p* C) \" U; O
  27.   {# K, V4 H# R# R. L: J2 R
  28.     /* 使能预取指 */
    ' s  R- u* q8 ^) [8 Q8 s
  29.     FLASH->ACR |= FLASH_ACR_PRFTBE;7 B1 ?% j; [: W9 [

  30. ; @; X& x+ M3 ?, {7 D: M8 m
  31.     /* Flash 2 wait state */
    0 X, w, ^2 g$ j1 D) x" F
  32.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    6 w" s$ D: C$ Y$ ]
  33.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;- p" W& x; \! q& Z, v- k  [

  34. 2 {& n% [2 f8 ?, h+ ~  q/ q1 Z

  35. 5 X0 `+ x/ d9 z
  36.     /* HCLK = SYSCLK = 72M */
    - Y  Z+ B2 j% W- I8 G& y
  37.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    7 J9 P' W+ R0 H. H

  38. . ]3 M: @9 d: ]+ f
  39.     /* PCLK2 = HCLK = 72M */
    ; K  G- Z, f$ `: t
  40.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    7 m/ Y- m4 r8 g) T% i  f8 f" [
  41. 4 Q+ o$ y3 T+ M/ p* ^1 B
  42.     /* PCLK1 = HCLK = 36M*/1 ~2 k+ E: g. t" t
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;5 a5 B$ l  g- E. L6 H
  44. ' {; _' C- w+ a( g# t
  45.     /*  锁相环配置: PLLCLK = HSE * 9 = 72 MHz */9 h+ a9 {2 [: k4 U; L( A
  46.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |- N. L9 C2 |$ T4 e
  47.                                         RCC_CFGR_PLLMULL));& J4 i0 Z5 Y7 e5 Z+ x6 V
  48.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);' x& q; i& G' M3 C, J
  49. : O) M2 q9 D/ c/ P& [) O2 G+ r
  50.     /* 使能 PLL */
      V+ W! c# T. W, m! R* S8 i9 }/ T
  51.     RCC->CR |= RCC_CR_PLLON;
    1 J* ^# T# I0 J

  52. 9 D& B' a' I9 p1 O4 S
  53.     /* 等待PLL稳定 */
    * S, e, o/ S* f9 r+ x3 W# M
  54.     while((RCC->CR & RCC_CR_PLLRDY) == 0)1 N# N4 \; Z! V# H
  55.     {8 L- C$ L2 p: a1 x
  56.     }
    " Y! K* X6 r) g8 N1 o+ A" x% ^
  57.     /* 选择PLLCLK作为系统时钟*/; f9 E) ^$ c2 g
  58.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    3 X8 c; k5 a. a3 _, t
  59.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;4 e# {- I$ `/ n
  60. / I* I# t- z4 c& H3 E
  61.     /* 等待PLLCLK切换为系统时钟 */' Q- m/ @; y. E' X
  62.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    3 F# e6 i3 P2 B4 J" ^0 S
  63.     {2 }3 y$ f' e7 t4 \) j1 C
  64.     }
    , _% _6 W' U. u  J5 v
  65.   }7 B& Q% g) J4 J$ M' e4 N
  66.   else
    9 i7 G$ a) `) q. O* b4 H9 j. u4 d7 ?
  67.   { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
    ! Y* _" X8 d7 ~1 V' r  G9 [
  68.   }
    ; ^- M- S( G, q
  69. }
复制代码

& A6 j; A$ K+ s6 l  Q1 L6 p# J* j
这里再以库函数形式中重新配置系统时钟和MCO:
user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的)
bsp_rccclkconfig.h
  1. #ifndef __BSP_RCCCLKCONFIG_H
    * D' W: M: q/ z; e/ |
  2. #define __BSP_RCCCLKCONFIG_H1 o9 O, C% c8 |. P9 ^

  3. " c7 h* r. k& x9 n9 V
  4. #include "stm32f10x.h"
    . ]5 J* j. B, K6 }2 e  C

  5. ; L9 ^& m+ p) |# n# B2 ?0 [, E6 R; Q# ]
  6. void HSE_SetSysClk( uint32_t RCC_PLLMul_x );
    " a; [+ g0 H- J
  7. void MCO_GPIO_Config();
    8 k1 w" z. q1 E' x  n' r/ c6 [
  8. void HSI_SetSysClk( uint32_t RCC_PLLMul_x );! i! n  e- H, G# c. b9 n; Y) D
  9. #endif /*__BSP_RCCCLKCONFIG_H */
复制代码
bsp_rccclkconfig.c
  1. #include "bsp_rccclkconfig.h"' t$ c$ P: k. ?) y5 t1 @. Z

  2. ! n9 \" X( b3 w- Z7 c
  3. void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
    2 Q4 H) w0 |8 M0 ^) e8 G7 _
  4. {
    $ Z, {) L8 G# h
  5.     ErrorStatus HSEStatus;, j7 Y$ H! v, L! Y' J% h( Z& A* K

  6. 7 p* m0 q  c" _5 L/ u
  7.     //把RCC寄存器复位成复位值
    3 B1 O* X% I) a- J
  8.     RCC_DeInit();- W& b0 |. D; L$ S% y* |+ }

  9. * d* e: r2 ^# F, d+ \
  10.     // 使能 HSE" o, I6 n9 C- L8 u: u, w1 D
  11.     RCC_HSEConfig(RCC_HSE_ON);
    & h7 L8 l+ c6 ^: y' g

  12. ; k0 i4 E: [; q* R) R0 w" ?, \) f
  13.     HSEStatus = RCC_WaitForHSEStartUp();& Y! t! M2 t  m1 b
  14. ! }4 M4 W9 s; f) O/ X5 O; o
  15.     if( HSEStatus == SUCCESS )
    9 T9 z& C; C3 H+ m. E2 H
  16.     {
    2 {4 x7 |# \% Y% C  I
  17.         // 使能预取址
    . ]/ M" Y5 K% M" F$ z! l
  18.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    ; _! o9 t0 g8 G4 T5 t) d  d
  19.         FLASH_SetLatency(FLASH_Latency_2);
    ) k0 Y  A% o7 E( z

  20. ) n! |: Y: U4 ]* x7 g# J
  21.         RCC_HCLKConfig(RCC_SYSCLK_Div1);
    2 M& v& k# K$ [$ o5 H: H$ M
  22.         RCC_PCLK1Config(RCC_HCLK_Div2);& J) o) p4 I9 n( L6 c1 C
  23.         RCC_PCLK2Config(RCC_HCLK_Div1);
    - r6 v3 {' P" w+ q/ s) E
  24. ; z, D! S% j0 ~7 W1 f( z9 m
  25.         // 配置 PLLCLK = HSE * RCC_PLLMul_x4 L( H8 z0 F! ^) |9 n. A* j
  26.     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);3 s1 z: H1 ^6 i7 z

  27. , Y. f( c! p& A. R2 ]' r) m# P' j
  28.     // 使能PLL
    - ]8 A6 L/ A! d6 \) B) U* p
  29.         RCC_PLLCmd(ENABLE);
    / [/ g3 \$ h8 J0 W5 l3 q

  30. / R; V, h$ O* t. e* A
  31.         // 等待PLL稳定
    # b! E# L1 C6 c! [  c  c
  32.         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );3 K0 O* I; f# t! R  S9 u

  33. # J: B: B+ r8 j. _; l
  34.     // 选择系统时钟* A. Q5 n- Z4 o! U" n
  35.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);& ~! O0 J  i: u. j  w

  36. " {# m2 Z, j" U, ]. w
  37.     while( RCC_GetSYSCLKSource() != 0x08 );4 x# \" a& y1 S  h! S
  38.     }$ M( C- Z9 G6 b3 x
  39.     else* c, g& D$ X+ }
  40.   {
      Q( k$ D# R( o9 n8 _7 P
  41.         /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */8 B/ I" O9 I0 {$ u
  42.     }. A# M$ q9 P( `, e! ~1 M. ^
  43. }$ |) j( T! W( F- X
  44. , }* d( v+ S1 y. K& b/ Y  V
  45. void HSI_SetSysClk( uint32_t RCC_PLLMul_x )
    & l# y) ~  L8 m8 N6 z9 j/ R2 N
  46. {
    / f9 p4 E5 E* W7 u5 }% |3 U. i0 Q3 x
  47.     __IO uint32_t HSIStatus = 0;+ R0 Y3 R' N# b7 t/ b- |
  48. 3 g9 W! a/ N/ u' t4 R
  49.     // 把RCC寄存器复位成复位值3 u; j6 ^; P- R! p; ]/ d
  50.     RCC_DeInit();9 ]9 R% p  x4 g6 |
  51. / t  d9 `& q7 {( ]8 H' `
  52.     // 使能 HSI
    - G) @$ X) Z7 n0 R. l5 Q
  53.     RCC_HSICmd(ENABLE);" \8 P* G  S; l# M5 o$ }& ^& x) X; A

  54. , U* ^# i. h- C+ {- u) W
  55.     HSIStatus = RCC->CR & RCC_CR_HSIRDY;0 p  J% ?7 }5 I+ p) F
  56. " J0 j8 o' ]2 f; \) `+ T$ {
  57.     if( HSIStatus == RCC_CR_HSIRDY )
    + [4 I! D  K- n' {" {) ^
  58.     {& c* D5 z, v+ C
  59.         // 使能预取址: O4 ^' h1 W, R. k+ t
  60.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);% K8 d. e0 Z  c0 I, U  x0 J9 R
  61.         FLASH_SetLatency(FLASH_Latency_2);
    6 _  T% i2 Y1 W/ f& }( }; a
  62. ; c* O2 X- w! N9 H7 J
  63.         RCC_HCLKConfig(RCC_SYSCLK_Div1);
    $ L- x' v; H, z; |! v3 T0 C' K
  64.         RCC_PCLK1Config(RCC_HCLK_Div2);
    ; D$ V. _: E! W9 N7 [; z
  65.         RCC_PCLK2Config(RCC_HCLK_Div1);0 c; {9 c  @/ j; F. d* t+ J
  66. 1 F5 u* x+ h+ S
  67.         // 配置 PLLCLK = HSI * RCC_PLLMul_x
    " L. h2 @; g" e, e5 ?, b% Q+ z
  68.     RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
    ( [7 G7 a" s7 @  L4 W$ u/ a2 V

  69. ) v( b4 @8 z: K- F* r
  70.     // 使能PLL
    3 c+ D. A5 h2 O' Y6 m
  71.         RCC_PLLCmd(ENABLE);2 X7 ~8 k$ t3 y5 I/ f" c
  72. $ x! Z0 w# n6 n% A+ n* |
  73.         // 等待PLL稳定
    5 x1 v" F9 X( _0 S+ C
  74.         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
    ' q& H' {4 x) B" T3 _3 J

  75. 4 T9 Q% J( s* V: C4 _
  76.     // 选择系统时钟
    8 D$ ?& @9 x- z: q9 O& x' {# z$ n
  77.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    9 q& o7 o! J: m! B# D4 d

  78. ( d1 L1 `" c& a# x
  79.     while( RCC_GetSYSCLKSource() != 0x08 );
    ! A1 ?$ Q6 D# S) e
  80.     }6 b& K$ r( i) w2 E' d
  81.     else( q6 d/ x4 [% s* D/ ]3 T7 [
  82.   {
    ) v! r& [8 {0 Y
  83.         /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */2 d9 Z, _: s6 h7 z  g. g; P
  84.     }/ J4 L3 n# E' [% B+ M* `& A
  85. }0 I3 t+ Y" q2 d  ^3 d9 [

  86. ! {4 K; a3 U: }1 k
  87. void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8! ?2 @% z: ]. K5 j( i; Q9 ]
  88. {
    ) x9 z0 ?# V( Y# [' V
  89.     GPIO_InitTypeDef  GPIO_InitStruct;/ T  A/ ]0 {9 ?* `
  90.   e9 H2 i% x. e' z; M% `. `$ @2 D
  91.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);8 k5 `& _7 B; ^
  92. , r) U; x; ~6 c
  93.     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
    ) ^( r% Y5 S# G( d: _
  94.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;2 B) o9 n5 s  }( ^: O% o
  95.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    ! i2 N0 I! ]" F- g

  96. 4 {+ H( V2 u% N
  97.     GPIO_Init(GPIOA, &GPIO_InitStruct);- B7 R4 V# {/ t5 k, T
  98. }
复制代码

( X  r, X4 J- i. [0 l
main.c
  1. 1 #include "stm32f10x.h"   //0 e( y0 G8 X6 _2 ?2 X# b
  2. 2 #include "bsp_key.h") a2 q  f/ r3 S7 B
  3. 3 #include "bsp_led.h"5 h9 w; {4 {- X1 o# r6 W
  4. 4 #include "bsp_rccclkconfig.h"$ m9 ^+ e9 b, H) L% s
  5. 5 void Delay( uint32_t count )   //软件延时函数,但是实际时间间隔取决于系统时钟) M# y. G) _- D6 J9 V& I2 e
  6. 6 {. d6 ^  d" G% Z/ r: e% s
  7. 7     for(; count!=0; count--);
    6 o" `# k; g4 K5 O+ t, w& V
  8. 8 }
    1 x, w  B+ ]* g# e8 A1 U' }* x
  9. 9
    , h2 n+ F+ l! j3 l8 h) V, |
  10. 10 int main(void)+ c  k2 C) i0 \( }0 X: s6 W# L
  11. 11 {7 ?: M; u  L; u0 [' J6 u+ j
  12. 12     // 来到这里的时候,系统时钟已经被配置成72M
    9 V5 u! ]- G1 R
  13. 13     LED_GPIO_Config();
    $ |8 k; I) Y5 l& W2 {7 G
  14. 14     KEY_GPIO_Config();
    9 A. X( M4 g5 N
  15. 15     //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M16                                    //HSE=8MHZ,PLL九倍频=72MHZ5 W; V  m% r% S0 A. ^
  16. 17     HSE_SetSysClk( RCC_PLLMul_9 );
    7 [" G; A8 V2 D! D5 U1 r
  17. 18                                    //HSI/2=4MHZ,PLL十六倍频=64MHZ
    6 \# v: Y& o/ w9 ~+ P9 }8 m8 w
  18. 19     //HSI_SetSysClk( RCC_PLLMul_16 );) N1 W8 `5 _7 c' I& h" z8 [
  19. 20     ) P9 i( Q! P# K7 ?7 b, R) v
  20. 21     //MCO的GPIO初始化
    ; _. y+ \, O  Y% X/ @8 V
  21. 22     MCO_GPIO_Config();
    5 `' R( \& B3 {4 B9 W: ^/ ?
  22. 23     //选择系统时钟作为MCO输出+ p. f8 }, k/ U7 X+ p& v  o
  23. 24     RCC_MCOConfig(RCC_MCO_SYSCLK);  //PA8接示波器可见
    * g! p- |% R1 |1 d
  24. 25     //RCC_MCOConfig(RCC_MCO_HSI);
    , D( n0 \$ g  J" K
  25. 26     
    % p5 ~" T  J  e0 L$ x5 r1 P
  26. 27     while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化
    + w' j. H3 a- w, t5 {
  27. 28     {
    8 e" e: [# u2 q/ i2 Z' x& _
  28. 29         //8 U8 p$ g3 T0 V% t
  29. 30         //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON )0 Y8 ?$ F5 y5 Q) I  Y
  30. 31         //    LED_G_TOGGLE;
    + M1 ?6 N7 R  J0 N2 s
  31. 32         
    + Z/ o- [% |# b7 `3 V+ R, G4 w
  32. 33         LED_G(OFF);& y: j+ p! c. }: m# K5 \
  33. 34         Delay(0xFFFFF);8 |( P& s4 H' K2 U4 q% c
  34. 35         / w# S, m" _3 y8 L0 s1 d4 }
  35. 36         LED_G(ON);
    ( y  Z  X# Z" x# N6 \& n7 Q
  36. 37         Delay(0xFFFFF);
    6 ^5 F8 I) S0 t; |
  37. 38     }
    " S* P- |9 g6 _) R$ f  ~! R
  38. 39 }
复制代码

0 _# G, V. T# y+ y0 [6 f; T
赞 收藏 评论0 发布时间:2022-1-28 20:57

举报

0个回答

所属标签

相似技术帖

官网相关资源

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