一、系统时钟配置$ X8 W; G7 ^; J: o. k2 ]2 m
4 E" G- L) D$ Z: ~" q$ S3 f
STM32有多个时钟源,分别是HSI,HSE,LSE,LSI。
# M' @, n! k: j1 t u+ u
4 ?6 y, f5 E% t" dHSI振荡器时钟:* [% g: S9 D4 Q9 J9 w
+ M2 r& K4 B7 f系统上电默认时钟,内部振荡器8MHZ,可以直接作为系统时钟或在2分频后作为PLL的输入。时钟频率精度较差。- C$ P* L$ A0 W6 e$ o8 \6 @
4 O1 e, ?+ V" W, NHSE振荡器时钟外部:
* d% L8 A- ?' p o- {4 P# Q# W# _: S2 j/ p) m) d. n
提供非常精确的主时钟,STM32F1系列的板上为8MHZ,STM32F2系列的板上为25MHZ晶振。经过PLL倍频:作为系统时钟。
* ]+ I: n6 U( ]1 m% C S* r6 F: \) h% R
PLL时钟源输入可以是HSI时钟的二分之一,或者HSE时钟。
" y6 A5 E4 v. d6 ~" A/ _& j/ @9 Y) Z2 n
LSE时钟:) p+ F; x$ ]$ q+ ~
% T- D' q" d- w! g
LSE晶体是一个32.867k的低速外部晶体。提供实时时钟。一般专门用于RTC,等到RTC模块时再使用。
! o+ r4 J- U' b8 J3 p; O# n' }6 w8 {' b7 Z; I$ D
LSI时钟(Internal内部):- r7 m% k0 j* z
# H- H) S; J7 b9 B
LSI的RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保存运行。为独立看门狗和自动唤醒单元提供时钟。LSI时钟频率大约40KHZ。一般用于IWDGCLK。( \' t& }' Z$ R; q1 K" Y
|. ^) x+ [* L+ V: \通常的时钟选择为HSE配合PLL使其工作在72MHZ(STM32F1系列)或者120MHZ(STM32F2系列)。3 H/ ~! {) G% w' s g- r
+ m" E7 D% Z; Y# b) q3 G. ]& S% T0 w
) o6 r8 d0 b( ^ e
STM32F1xx系列
+ f3 s, _, E$ w, N) ~7 C( g* Y' J5 c# ^' |+ R1 N
7 w* t: u3 J; H7 {3 w6 Y9 b: Z) B" j; r# Y
STM32F2XX系列 " d2 Q% ]8 A5 x2 I$ f+ h
3 U, v; G& E* g2 d, l$ N# O+ Z5 SRCC_DeInit()同SystemInit()的区别仅仅在于SystemInit()多一个SetSysClock()。SystemInit()包含了整个内部时钟到外部时钟的配置,但配置的频率不可调,如需调整频率,可以自己用RCC_DeInit()再配合其他操作进行。
4 e5 T: j9 A6 X9 |! e H9 Y" Y( ~- f3 Z0 W- x* A. D8 |$ h0 @
配置时钟流程:" _' ^, G% ?4 K# S
4 M4 z2 G. F" V( B1.将RCC寄存器重新设置为默认值 RCC_DeInit;% F7 C w# w( C6 q
% [- X9 z; ~& e: |2.打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);' Q2 p+ }8 H" ?3 J K
8 @) J1 q6 O3 ]/ j3.等待外部高速时钟晶振工作 HSEStartUpStatus =RCC_WaitForHSEStartUp();
! c" w3 S2 j) q& k6 e* l
- O3 H4 J8 t: d& c. o4.设置AHB时钟 RCC_HCLKConfig;
' i* _4 c w$ s4 Z3 o# ?; \, j% z: Z& L! v3 l" ^6 S9 O
5.设置高速APB2时钟 RCC_PCLK2Config;
- a: N$ u5 Q- Y3 d8 R6 p
6 b3 Y# N. s' x3 Q* V$ e& V/ o" r6.设置低速速APB1时钟 RCC_PCLK1Config( i+ l0 F7 _4 c0 x1 o
9 H4 w/ D. j. K- ^* }7.设置PLL RCC_PLLConfig;2 v6 C8 s- e) L- D& q/ k
! Z3 I2 s- F+ L5 O/ [7 w- Y2 w8.打开PLL RCC_PLLCmd(ENABLE);# h" |# y0 F; w
! ~& f) O/ _- | W6 S9 F8 j9.等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);6 K# n1 Z, Q3 G2 @# M. a
+ O/ u& a) s! n# U' {
10.设置系统时钟 RCC_SYSCLKConfig;
+ k2 \+ W6 [& I) T; _
% v2 A+ R0 a8 L11.判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08);2 Q2 k+ R( N1 x
$ w+ d: ^/ L2 G, ~0 }4 L
12.打开要使用的外设时钟 - RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd();- X9 A5 J7 z, x
- 3 @% K1 G/ Y% E' u+ z
- /*******************************************************************************/ T8 B* N, i/ L0 m% G" C; L8 i: o$ V
- 6 ^; K! z; Q9 ?/ n
- * Function Name : RCC_Configuration" h7 Y- F$ r6 g) v. e
" A# d1 i0 B0 v. j6 L- * Description : Configures the different system clocks./ J- C3 U6 T* g
- 3 y H7 o3 K/ r/ y+ H
- * Input : None% K9 S. A. {5 h+ K7 U3 r) |
+ O- p+ k& j* m* L0 j0 N* V2 O9 g- * Output : None4 c) t# C W0 O3 Z _
8 X# M% K6 q" G# w" S$ `$ L5 h- * Return : None: R, p+ l8 g; e
- ) L8 U/ I9 s2 t/ x- @2 w
- *******************************************************************************/
9 m1 H( A" N- m! q# A
' \0 x9 \/ F7 c! |% q+ Y- void RCC_Configuration(void)
3 I6 Y, Q4 v$ e4 M1 R
, E! Y: }3 Z' ?' s: V2 q; I# F- {
G% N! f$ j' Z! S' [# v/ B - " @/ l9 P: X$ n8 n3 t
- /* RCC system reset(for debug purpose) */4 d7 q0 v# x' [% t% T- w
- * P3 v" O8 }2 L$ v+ |" ^! ~1 U
- RCC_DeInit();
; J! C2 N& d2 `: ?% J- v0 K
# w3 d# _0 ~2 D$ Q
0 O7 N+ B/ X0 A: o2 A- w
/ z+ E _, ^6 ~' X9 @; \1 g/ h4 k3 b5 ^- /* Enable HSE */: V5 R8 X1 C# h7 S* u( ~8 [' s9 m
- / l; g% M' n0 ?) I8 K+ [
- RCC_HSEConfig(RCC_HSE_ON);9 w% V4 V6 k4 Z$ [2 l
+ X" [- `, t: F$ O- 6 t- C% u1 Z) r
8 i' |* b+ U7 c/ c: _) g1 T0 b- /* Wait till HSE is ready */
& |; Z- V3 [' {- [ \ - ( M. l( a) c& q9 x: s" e2 W
- HSEStartUpStatus = RCC_WaitForHSEStartUp();
1 _* |" X3 l7 u# C, @7 b
% A' W" c5 G. `- % x w+ Q3 { `# E5 g
1 ~$ C; l" J2 A4 k, b- if(HSEStartUpStatus == SUCCESS)
- i8 ?* W# X, u, u% r
/ G! B" `0 v- A1 x8 F% B- {
9 r' N) Y( g; ^- a5 ?2 ` - 6 P* b7 ~& \ E3 w
- /* Enable Prefetch Buffer */7 ]" m0 C4 k8 L: I4 a: _- U" z% D
' h9 ~! }- p1 ] v8 ?# N: Q- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
* x) c' P h+ k% w, D4 T0 D2 ? - " t* l( k1 }- y' {7 M$ d/ H3 K0 k
- 0 Z2 |% ]) j% { f! |$ R' Y
- $ j* T: V; w# i$ [
- /* HCLK = SYSCLK */
3 D5 M% s+ d. X% s8 N: Z2 h9 t - / I6 \6 |, A3 L+ m1 Q+ c7 F
- RCC_HCLKConfig(RCC_SYSCLK_Div1);
' }0 r! v% u0 S# `; d4 F- X - + h. o0 |8 g$ k" p( R, p" J( x
- + x j- o( a9 |: ^
- _0 L2 g3 E- m. k4 c( \) O* `- /* PCLK2 = HCLK */* ]: U/ f* X, [/ a9 c/ c
f+ y8 w# {' M+ G! _- RCC_PCLK2Config(RCC_HCLK_Div1);' H' p+ C: k& f* x, ?. U% }/ j7 h- E
- 2 d8 w: t- [0 d3 Y
- 2 P6 F* H; n; C( }! N( Z W
- 5 y7 b/ m: D: `. n- b
- /* PCLK1 = HCLK */8 b- ]% H* x- ]: ?9 U8 H
4 ]0 g# G6 @7 b- RCC_PCLK1Config(RCC_HCLK_Div1);9 g2 v7 m2 X+ [6 Q4 L. d7 J1 f
6 X' u X: J, @& ]+ u- ( m5 y" v' y/ I6 _# l% y2 m
- 6 i5 K7 l# x9 w+ r3 Z N+ t5 K
- /* Select HSE as system clock source */9 P* d9 h! `! q! E# W
9 D( x2 s7 r3 o3 Y* ~- RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);. _+ Z6 Y1 R% L( }( l* x3 e
9 a# ~& m# J5 m0 \2 |8 d. Q/ [
. G1 D9 _- \" H2 U5 ]2 ^- , \) @& y3 O7 U7 j
- /* Wait till HSE is used as system clock source */
! j' I8 p/ K. A! U: f5 ?
, J# k: l, V6 q1 G8 g- while(RCC_GetSYSCLKSource() != 0x04)/ _: L/ r, r; t( n1 D) x
4 P. e$ B" [8 I- {& K. g- S J0 O
- : g$ x/ w9 C& t+ v- V+ M
- }
1 ?% z) E: V6 u9 Z3 U; W. V% U' t( | - % ~- U7 D+ X/ d% k9 |
- }% m; _; J7 ]/ v
! L, P9 s$ \6 d# o# n l- XXXXXXXX; //分别为其他外设的时钟配置。
4 L2 @8 l! ?5 C- [) P, `9 P
9 b7 t z: M/ h# L3 g" e- t- XXXXXXXX;
# H0 O0 U- j8 N) m. f+ ] - * Q+ D$ ^3 c& O+ u& ], k g
9 V. I, g. x0 h0 d% }: C2 K8 h
, K9 q- G! M$ G6 c- XXXXXXXX;7 G* `: C( _ j+ }% ~( \9 J
. q( a8 G$ g. _6 @( ?- }
6 r' B; M3 v& ` `. J
复制代码
: }9 D4 D6 N6 p; R9 W! N' e
0 r% S' ^5 `) o; Y7 q: P+ I0 W( i/ l二、关于PLL设置& E2 C( t+ B0 o& F/ U( \ c
# j) @* K7 q- W, L, m! p2 GPLL的设置主要通过函数:void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ, uint32_t PLLR)来实现。9 o" i# W. n8 o( `* B9 |( {
5 G! |8 `* q# j主要讲一下PLL值的设置与各部分时钟的关系。函数中涉及到6个量的设置,第一个为内部时钟或者外部时钟选择,后面几个为PLL值的设置。! O# C% A8 N! i$ k/ y
( R. Z. l- T- ]+ |
l RCC_PLLSource选择:
( d" N8 s# J& A1 _) I& X; G$ h
( |5 P* l1 d+ u. ?( e- e( q+ X; l- tRCC_PLLSource_HIS:HIS内部时钟选定,频率为16MHZ1 Q$ d' m- \) f. G* p4 p% E
; P, `- @0 z$ I" V( U; o+ b8 `, ~
RCC_PLLSource_HSE:HSE外部时钟选定,频率可自选,4MHZ-26MHZ之间,系统默认25MHZ,如需改变,则对stm32f2xx.h中第70行的
# b4 p3 w+ Z# c! {8 {- j. i% m+ U3 H- M" ]/ z ~8 R$ e
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */0 V! Z' _5 R2 i/ R$ L/ l( w
8 C' L# u3 @4 m% l4 }6 J进行修改,改成外部晶振的值。
; T! y0 Y3 P: W' W7 z% B' J2 r7 C) i0 r7 s" v9 t. m6 h
l 通过选择PLLM和PLLN,来计算得到PLLVCO,计算公式如下:! \# H/ |9 O5 k$ Z. a2 Q8 }* L& k2 r
- q3 d. C' o- B! c' l! L" gPLLVCO = (HSE_VALUE / PLL_M) * PLL_N。" r j( t. g% `# X+ e3 U
6 M' Y* \4 r1 v# g3 x7 M
PLL_M可取0-63,PLL_N可取192-432。' F! @6 M4 ~$ B6 v2 V& b
# m i* U" L" |* J$ w7 G, r
l 通过选择PLLP来选择分频数,以得到系统时钟。计算公式如下:% w' x' C9 V; K- X- ]
|4 f& R$ h4 ^# Y4 j% m4 z+ iSYSCLK = PLLVCO / PLL_P,切记不要超过120MHZ最大频率。( u; g; }% t+ ?! j8 Z
- {5 I/ m' T9 O, jPLLP可选范围为2,4,6,8。
( z( p+ G# h$ c; b7 N' r
8 P; J8 c! O/ i1 y/ _l 通过选择PLLQ来OTGFS, SDIO和RNG的时钟。计算公式如下:& T; X, V V5 k
. L$ e7 C0 x! c- l, tClock = PLLVCO / PLLQ,不能超过48MHZ。1 v8 Q6 c$ L [/ u# I) P2 @4 r5 J
" I' @- A6 |0 ~ bPLL_Q可取4-15。/ Y9 ~' e9 ~- H1 D7 X9 Q
) x; P8 L- W6 ]1 ]8 S9 U
l 通过选择PLLR来决定I2S的时钟。计算公式如下:4 y; x- G4 W' t0 \2 A
1 \( @' P# D# D; B$ l1 k% U
I2SCLK = PLLVCO / PLLR。
N% K7 |. ~% O) i1 I) X1 H, n7 L. r7 @% u ~
PLL_R可取2-7。
' v% c7 f9 ^; `7 y2 Z, V3 }# E; Z
6 Q+ y- k1 i" I8 Q3 W: X @' I+ i% W" _" T) Q- y
3 ^( d' c4 J: p, C6 L |