一、系统时钟配置
6 V. e' h$ h" ^2 N. s2 b5 b6 _8 _4 Q% ^- Q% \
STM32有多个时钟源,分别是HSI,HSE,LSE,LSI。) L2 f& z0 P& [# B! t% ]
: ^/ x# @5 a# g% ^HSI振荡器时钟:3 E* l+ _; y" a8 {' k( Q
+ [0 f! D0 F, j; E8 b系统上电默认时钟,内部振荡器8MHZ,可以直接作为系统时钟或在2分频后作为PLL的输入。时钟频率精度较差。2 E E/ h% z" j6 I- g; V) p; T5 y
7 B5 C* E' D6 h. @8 @, a
HSE振荡器时钟外部:% J, a: A6 x4 f* S f
0 w# h# r! S. O提供非常精确的主时钟,STM32F1系列的板上为8MHZ,STM32F2系列的板上为25MHZ晶振。经过PLL倍频:作为系统时钟。; b! s; k' S2 m) {7 V+ I* _9 q
) y9 M0 S+ t9 ]# MPLL时钟源输入可以是HSI时钟的二分之一,或者HSE时钟。
7 M: q& n1 l$ h; Y/ L& x7 S. }1 q8 g0 T- d9 ^9 j+ o
LSE时钟:
6 V f0 e/ r/ } n! Z4 C ?& F* @/ y5 y3 q) l! p! D" |
LSE晶体是一个32.867k的低速外部晶体。提供实时时钟。一般专门用于RTC,等到RTC模块时再使用。
' I) j/ V1 t1 ^9 D
' N, s& ]% K: n; v$ fLSI时钟(Internal内部):+ V# P$ L1 S* f, G% U) T
+ j3 G$ }% A. O; S; ALSI的RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保存运行。为独立看门狗和自动唤醒单元提供时钟。LSI时钟频率大约40KHZ。一般用于IWDGCLK。6 t; y# u/ K! v4 ?9 B3 i
) Z. b, M- z" Y
通常的时钟选择为HSE配合PLL使其工作在72MHZ(STM32F1系列)或者120MHZ(STM32F2系列)。
) z& H- G1 ~6 G, v2 n$ G2 E+ Q% k i' l% e! r9 H; _
, d1 [6 V8 R+ s4 _# L3 I
/ H5 `; A1 k1 q# y# q
STM32F1xx系列 0 z% ]) m: M4 A5 \3 r4 M7 E
" ?: q7 H% M0 @5 q+ A2 ^
& r7 h: d7 S" W- _- N: x; ~* _6 |; P f; U
STM32F2XX系列
$ C z: g1 R, I2 W9 K/ R* h1 O. W* @6 o! A
RCC_DeInit()同SystemInit()的区别仅仅在于SystemInit()多一个SetSysClock()。SystemInit()包含了整个内部时钟到外部时钟的配置,但配置的频率不可调,如需调整频率,可以自己用RCC_DeInit()再配合其他操作进行。
, K* J* W& z* ~, p3 Z; h9 I# G4 ~ T2 b( y1 E- y! r2 L& l
配置时钟流程:' [7 H; y- z# ?. p$ V7 t' t
7 ?% ^0 M: L3 ]' h2 `9 k% G7 f1.将RCC寄存器重新设置为默认值 RCC_DeInit;" a- q7 V, v# j" \- [
1 u5 P' A. b% }# _9 ^2.打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);' N( [3 F) o; E. R6 ]
w1 O; a" i- T. T! @! i3.等待外部高速时钟晶振工作 HSEStartUpStatus =RCC_WaitForHSEStartUp();
$ O5 f( K' D9 m7 n% Q" e+ o
: m* N/ c) |% h2 Y8 k! Z% I4.设置AHB时钟 RCC_HCLKConfig;% l; E# V x1 G3 t: c# e7 C, Q
/ r) Z, I+ p+ |$ [6 x1 b) c5.设置高速APB2时钟 RCC_PCLK2Config;) G7 _* D4 b) p& O `) O
' V; @ Z6 _, G9 v8 n# V0 ~
6.设置低速速APB1时钟 RCC_PCLK1Config" I5 @5 z c& Q- \
. y, V. A$ I4 @2 l/ D/ W' M& g5 V7.设置PLL RCC_PLLConfig;& \8 k' Z7 b {
1 q* t" `: c6 X- l# t2 X! u8.打开PLL RCC_PLLCmd(ENABLE);' m% g# J9 u( _4 I* a/ H+ `/ c) S/ U
8 m$ o9 n! {8 R* _. Y! I/ R7 j
9.等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
. }2 J2 ^0 U3 z
( o. ?( R& J. H7 Z& Q; h% _( [3 L10.设置系统时钟 RCC_SYSCLKConfig;
" L N' [% L+ N, {: |+ C; x
9 P! {& U" o& h. Z/ a. s$ C- H11.判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08);; P9 U! S" A/ g- |/ v
s4 K' u0 s0 A$ |9 t" ]
12.打开要使用的外设时钟 - RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd();
4 h# r! S9 O/ Q5 V! N1 }8 @ - 3 M& l8 N) ~1 B2 W# e
- /*******************************************************************************
# u9 V6 w7 {- @" l" A# I/ B1 m- ^
& \, z) o- F$ A. G- * Function Name : RCC_Configuration
$ a4 h5 F s$ |$ t+ P
7 T# P. }* f( L7 e7 A8 Y- * Description : Configures the different system clocks.
3 W: @6 L; G3 B, X - : z- s @" t. ^4 O
- * Input : None, {7 R2 |2 D/ d$ T
- " H) W2 ~* r" ~# X- D* c
- * Output : None
" q* ^& ~; |: z5 n* k
( X( T! Y& y" N- * Return : None; a1 f# u& C7 U2 d$ @. T* O
) u8 q* M* Q' ~6 t* R9 n% y- *******************************************************************************/- f* x2 b- D9 ^2 x h2 L
, v @2 w! X4 X- @" @- void RCC_Configuration(void)
, p8 p D+ G. V, e h% x/ V( n
; V8 R! } @( G. e& i0 }- {: v. q0 H1 a$ H. V/ v8 N. U( h
; i! |) l* m; z6 m' M- /* RCC system reset(for debug purpose) */$ s8 m! o% J* r& h
( Q) b3 \0 {2 k8 m( l- RCC_DeInit();' E# O, t r% B( a. G3 S) G3 D. _
- + W& P6 _* K) t, `" d8 k" F, y# s
- " V* E3 ^! ~+ [
1 M% P' U8 J0 x( S1 @5 N- /* Enable HSE */* K t# ^1 d* B" z: `; a# J" b
- ( ^0 t, `' T# t7 e* M
- RCC_HSEConfig(RCC_HSE_ON);/ w, | c& a$ A
% D; k7 l$ r1 I' d9 ?( G- ) l. j: g; ]: r. E, @8 C
}3 K4 O' W. }. A0 t- /* Wait till HSE is ready */
( y: L: T0 U' t3 `: M; u
4 v3 I5 @9 d! j! Q- HSEStartUpStatus = RCC_WaitForHSEStartUp();
/ b- r- c6 q' j
. \$ s4 d. I1 Z- w9 R( \' q; L
# V5 ~* R9 z& }6 {! [5 r6 r0 I- . l4 E* V* U$ Y- G0 b
- if(HSEStartUpStatus == SUCCESS)
/ \2 r1 M0 b0 `5 _ - 5 W8 N; g% y- g' \
- {
% }+ P/ ^$ @5 a% o
7 a. F2 @4 M! g9 g s- /* Enable Prefetch Buffer */# ^* I9 D# h5 K2 h
R; u" Z' I4 C+ N- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
0 D( [8 Z/ V; z" [: _! Z
. b& J* K2 Z6 }! ]% |- + J8 Q$ N$ s3 y* V. c* ^3 p
! l) D/ i' N" }+ P, X3 u$ c- /* HCLK = SYSCLK */6 a& @1 R4 D3 `6 i$ X2 ~. t1 l
- $ f% w; u( U- m/ b. U
- RCC_HCLKConfig(RCC_SYSCLK_Div1);+ U4 W; a6 v& {# L7 _
/ R5 m- u+ g# N" R5 O, c4 F; q- 1 U3 J- @" k5 `, K3 o' |8 Z- v
S& ]2 X; A9 z5 b! i: |- B4 A- /* PCLK2 = HCLK */
+ E) r/ F+ z& r# a3 E+ p; P
0 F) V H/ y8 q3 T6 Q* h- RCC_PCLK2Config(RCC_HCLK_Div1);
0 I9 e4 w5 P) W0 J5 \ - # v2 e7 d& i: A. _+ w; ]( n3 ` E' g P
2 K# I2 s6 [; x2 c: R% |/ |5 J* }
& e2 H; X1 R1 G6 l7 e9 t. k% T/ n- /* PCLK1 = HCLK */( S$ g( j4 Y _$ i' C y; E, R: p
$ z& P; Z9 _5 U6 [0 T L- RCC_PCLK1Config(RCC_HCLK_Div1); u, Z9 k% W0 Q% ^1 w
) i! Q! w. s8 M7 B8 f% Y( h- 7 _8 n6 J5 P( V |. w% n
6 `/ _8 P! t, m- /* Select HSE as system clock source */5 e" d/ d! L$ _' X& p. P
: @8 s. f) f1 T7 a- RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
' t: @# r" Z' g* @; H. O% d0 a' g - 0 A8 l- |7 l& j4 |. F; G+ d# a
- 4 j, r6 F/ o0 Y
- G, ~1 Z1 N! ]' Y ~& A+ C& v# O
- /* Wait till HSE is used as system clock source */
% ~. L/ n3 |1 i$ [& O B - 6 g7 ]+ h% Q9 }6 ~& c* u
- while(RCC_GetSYSCLKSource() != 0x04)
4 `1 F0 a6 X1 H
. [8 m+ R5 ^8 `0 _2 k- {
, p6 r3 P) ^5 D4 S' S( w - 2 b+ T+ m% c- ^- H$ V- ~
- }% b+ R, d1 `5 W& A2 }
# t+ v3 x/ @: }0 J9 W+ j3 ~" }- }3 D; s+ _" x+ n2 h, _2 h
. g+ J7 {3 G5 L( l& ^. l' i; L( T- XXXXXXXX; //分别为其他外设的时钟配置。0 `. h t! `, @' z* j: x
- / [0 q' F3 N9 L. f
- XXXXXXXX;' |# `; y4 [% Q6 G/ J. M4 C
- 4 ~: {; V. R# T; D
- 9 C: ^0 h6 ~6 v5 i L/ |& i8 V
0 r& \5 Z9 u! D! }: q1 @- XXXXXXXX;6 f/ o& ]; r8 j% A; X, i, V, K
- ( y8 g+ E! ?% P) g5 n% v9 F9 C
- }6 A0 |/ F4 O. L$ R
复制代码 # {4 Q0 r% n4 C- \" V6 s- P" |$ x3 _: q
% H) w" i2 N( C2 j. l' ^& `) N9 ?二、关于PLL设置* ]/ e7 J: |$ o4 m
7 ^2 m% ]# N/ Y* i7 P/ L+ }& X jPLL的设置主要通过函数:void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ, uint32_t PLLR)来实现。8 C7 a" {$ S# @& M. o2 d
$ V1 h% w+ t' j! A主要讲一下PLL值的设置与各部分时钟的关系。函数中涉及到6个量的设置,第一个为内部时钟或者外部时钟选择,后面几个为PLL值的设置。
: c, d1 K) }8 c/ S2 j: c, Y- ]0 C1 P! g- F$ Y
l RCC_PLLSource选择:
' s1 f/ I( g" F$ [2 w& P1 j/ x% E% o5 L d4 U. O* y
RCC_PLLSource_HIS:HIS内部时钟选定,频率为16MHZ
$ R; X: K ~* J4 d2 h$ f% }4 c! m. F( k T- K4 z! g
RCC_PLLSource_HSE:HSE外部时钟选定,频率可自选,4MHZ-26MHZ之间,系统默认25MHZ,如需改变,则对stm32f2xx.h中第70行的
! r& U3 ^8 c- V: T1 S; _* M
( D1 [7 d! M7 M2 Y \#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */4 _2 a9 j! R+ Q3 T
; |( O5 T& D9 ^( L; ~进行修改,改成外部晶振的值。
% B, u" l8 w8 H/ T
5 b) R7 \, D: k7 Z9 Pl 通过选择PLLM和PLLN,来计算得到PLLVCO,计算公式如下:) n" M9 N1 U% X% @* i
+ F/ S) K9 E8 o3 G% p- Y" N6 V
PLLVCO = (HSE_VALUE / PLL_M) * PLL_N。
g2 c9 o' d2 O, c8 D- X
# B5 b8 x; B& u, m) s! y4 }PLL_M可取0-63,PLL_N可取192-432。& }- l9 W8 g( F6 @ D0 F8 C! W8 O" }' N
/ _: U+ ?$ c5 d2 z0 ], Yl 通过选择PLLP来选择分频数,以得到系统时钟。计算公式如下:
: e6 o/ P" [7 Y0 ?2 d6 V
/ \9 p" o6 g1 T. K" v( @3 ^SYSCLK = PLLVCO / PLL_P,切记不要超过120MHZ最大频率。! @: t9 e9 a; r( R& u6 g) n
/ O% X/ ^3 \. c! K) A0 i
PLLP可选范围为2,4,6,8。) y2 l4 P* T* P1 F' E
+ I4 `# y0 L ?! V7 v. L$ L' b, el 通过选择PLLQ来OTGFS, SDIO和RNG的时钟。计算公式如下:$ F" E5 o* C, w) Y: j! ?
, b4 k- R' R% `9 vClock = PLLVCO / PLLQ,不能超过48MHZ。4 G: _# f6 h+ ^/ U0 o( p, L
1 [2 D' u6 O( ^
PLL_Q可取4-15。3 u8 C0 q# A- p5 d" _; k
! ]) W3 v& C) i0 hl 通过选择PLLR来决定I2S的时钟。计算公式如下:
" I. S/ b- X$ \& n$ ?; W! c# | G
I2SCLK = PLLVCO / PLLR。" `5 b2 H9 d" Z | A' x' a
4 H4 P- A: J. B5 p" x. l, C
PLL_R可取2-7。: j" r5 ]$ b5 C5 C) r3 Q7 {$ U0 Q
5 W/ D' P7 m9 G; f* {% t, M
% g; q/ q$ B. N, |% T
* r; _3 R8 f% |1 T, G |