一、系统时钟配置
$ i' [5 p$ B# }0 ]5 h
+ c( D; R8 |8 qSTM32有多个时钟源,分别是HSI,HSE,LSE,LSI。5 E: A2 ~; x7 t
6 s: P2 E. X/ g$ X. @
HSI振荡器时钟:
( n+ S/ \/ n" C8 O8 }+ I; ^% ?% @# R* v
系统上电默认时钟,内部振荡器8MHZ,可以直接作为系统时钟或在2分频后作为PLL的输入。时钟频率精度较差。
" f: G. [3 j j" G% L
4 m {1 Y f! ^+ zHSE振荡器时钟外部:
/ B$ C; d, E5 U6 m' n! H, M, Y. ]3 [# n ?# f
提供非常精确的主时钟,STM32F1系列的板上为8MHZ,STM32F2系列的板上为25MHZ晶振。经过PLL倍频:作为系统时钟。
7 y6 D7 p$ P# L% c0 E5 j$ W
; y* _; i9 e0 x2 ^" i$ Y/ cPLL时钟源输入可以是HSI时钟的二分之一,或者HSE时钟。1 u6 A; n: |9 g! d
& w% {" Y' y0 y; lLSE时钟:
- k* {9 l+ x1 M* E1 ~: @5 t" l0 H$ Q, V3 X+ J6 w
LSE晶体是一个32.867k的低速外部晶体。提供实时时钟。一般专门用于RTC,等到RTC模块时再使用。
9 d& X0 E( s! t. z) \8 K) b) k' ~) l" h: S% O' d- [$ ~/ C, _
LSI时钟(Internal内部):
q# [0 m/ R" _6 g* i9 E% Z, H* c A
LSI的RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保存运行。为独立看门狗和自动唤醒单元提供时钟。LSI时钟频率大约40KHZ。一般用于IWDGCLK。& ~% U7 Z2 l4 o" w
% ]! S: J6 }7 y' X2 g5 H通常的时钟选择为HSE配合PLL使其工作在72MHZ(STM32F1系列)或者120MHZ(STM32F2系列)。
: g( z* l' y, E( x4 H: |9 _
; r. H o7 T% {& j3 c3 t0 B4 L9 g4 b
0 {( p7 u! f9 }8 @) \
STM32F1xx系列 , ^/ Q9 ^) t6 O2 V
3 V P$ Y+ u/ ]3 w- g# }
9 ]. p7 b/ F9 J9 U+ q' R6 f, O! z% j. E, {" ]
STM32F2XX系列 . {2 t" I0 z5 {* ~2 {& Y' S y; m! H# `
( p( a& M+ @& @' \+ B
RCC_DeInit()同SystemInit()的区别仅仅在于SystemInit()多一个SetSysClock()。SystemInit()包含了整个内部时钟到外部时钟的配置,但配置的频率不可调,如需调整频率,可以自己用RCC_DeInit()再配合其他操作进行。
; h/ J: N& r/ P% I" O Q
& P1 i$ k3 c0 t# u9 I配置时钟流程:
1 e0 _& _5 L0 t9 m( c1 n' l- p" ~- d* J' S- ?
1.将RCC寄存器重新设置为默认值 RCC_DeInit;
8 `4 b" @/ ?" V2 k4 B% k' X" s6 b1 h( v% y$ g
2.打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);
* `6 p$ P$ U/ ^- Q9 F7 B$ I! r; @
/ ~- Q$ y0 s! E3 Z( R+ o; S6 I3.等待外部高速时钟晶振工作 HSEStartUpStatus =RCC_WaitForHSEStartUp();
9 o3 f9 X' g$ f4 q. A4 C; j( u) G$ x9 f7 I; q5 [# j- T1 v
4.设置AHB时钟 RCC_HCLKConfig;, q; H5 D" f9 E! I
$ K h6 q& _. m, l1 c0 H% z5.设置高速APB2时钟 RCC_PCLK2Config;) Y, a8 c- Y. b- l, W$ F
& X; a5 d6 |& E* @6.设置低速速APB1时钟 RCC_PCLK1Config: X, j% d9 e( V2 Y$ S( D
/ Y) b6 p8 M6 h% X4 A |
7.设置PLL RCC_PLLConfig;( [. `, x1 q- P) l
( C' I* _$ x# M+ o# Y- V8.打开PLL RCC_PLLCmd(ENABLE);, r5 y' M% O, e" g- `! e6 b
& o9 G3 Q! w* Z( b% Q9.等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
: D! I% u* g; O
# h1 ]3 |0 O' Z7 [3 v( `10.设置系统时钟 RCC_SYSCLKConfig;
# M6 U1 m5 D5 T: ^8 h. N: F8 c+ X6 S$ k* X/ d1 Y- I# B( t7 ^; n
11.判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08);, T" j; |# |$ }/ c& U7 M
' T1 n! a4 }+ i12.打开要使用的外设时钟 - RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd();
0 G6 C- a2 `7 B$ M: @ - % V% X5 h% d. U3 ^0 q
- /*******************************************************************************7 z7 w# b6 h) m/ C8 f
: }" K7 i* M3 v- * Function Name : RCC_Configuration
* ~, E7 R% q4 B! H7 ~6 m! T3 R' E
" C+ z: X( a9 O; y n- * Description : Configures the different system clocks.8 l' Q" h& t' ~4 l6 h3 q% a* g
4 J) m4 J; @2 c# e' P/ M+ C, @; V# T- * Input : None
8 l% w0 `( a; {2 w% m - ! C t$ i6 H* [$ o5 S
- * Output : None
$ k3 X/ D Y7 m! z2 H
! [8 V- ^7 @ C) z# X1 p! P- * Return : None
! d/ `& j+ j. W5 |
* P0 X+ r. y1 X& a% p6 q$ s- *******************************************************************************/7 \/ b- P, D" }
- * I% m- D4 E9 p; z8 W2 R, I
- void RCC_Configuration(void)
1 h j t: M# b [% D; @ - 9 |/ W- L+ \" Q& b. H
- {
5 A9 O. R7 B( k3 O) W( p
9 K) L) Z- g3 K4 \# w$ o& L- /* RCC system reset(for debug purpose) */
) y6 i- `2 _: r8 _8 \ - 0 ~) i3 ?$ L6 q2 [
- RCC_DeInit();: c& r; C% ?' d+ G& Z% q
) t) X! d% c' F8 `# G- # W+ d% y6 @) W0 |. ?* z( r) w
. b" k0 S% c) W- /* Enable HSE */
7 }& S1 Y- J h; u - ( k- i; i! b1 l( G
- RCC_HSEConfig(RCC_HSE_ON);
/ Q% |' C9 F/ k/ R
# B& i3 u( D* j+ U/ M$ @- % H. |, z9 H* e$ R
- 1 l- D8 ^- V$ J+ U
- /* Wait till HSE is ready */7 [- g: }: T$ c% ~. m; K- X
0 i) U# z7 L0 \- i; \* k& Q- HSEStartUpStatus = RCC_WaitForHSEStartUp();
, e3 }' O- R: Y+ }9 b - X4 u6 r2 r) ~" [+ a: X Z
- ( `. a9 [* C2 f' M6 q
2 p$ K7 R: `! F- if(HSEStartUpStatus == SUCCESS), Y2 J# \3 z( R0 z
- $ P1 \$ ?0 u( h. o0 n
- {
* |' \- J- E* S5 ~% H0 m6 H - 3 z, J; D% I; d( n; h0 q1 E8 s' d% f/ }
- /* Enable Prefetch Buffer */
; A; }% s) ] C1 Q. G7 k+ g2 _
9 h* N8 ~' U/ H$ u0 M- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
$ y/ W9 m: I- U - * q$ Q; e2 i; f4 l) e
- 5 B: U/ U- e2 [
- 6 a' \5 A0 O# ~% f, N
- /* HCLK = SYSCLK */
* O( H, p P4 D6 c3 R. c
1 J6 u; b6 Y4 |8 k- RCC_HCLKConfig(RCC_SYSCLK_Div1);
6 a6 F J+ g& d/ \" w* _/ Y H - ; @2 p) O9 d# N9 ] R
- 1 T# ~) F% g$ ~- ^
! z% ^, v5 f0 M8 w/ z9 z( d0 W5 q5 F- /* PCLK2 = HCLK */* ]4 P) t: V4 _& y W% }
4 R4 J7 f1 a$ |) Z; d f5 T- RCC_PCLK2Config(RCC_HCLK_Div1);( S. y, f. m s6 m5 g$ m- G
, D1 `6 S0 }( v% l/ G0 T
5 j. @4 O" y. P* O% `' w
) b" m; \0 m) c, K- /* PCLK1 = HCLK */
, h; h0 F1 e# d% Z$ O - 3 P/ N/ @1 R! z& C# {/ k2 c# L
- RCC_PCLK1Config(RCC_HCLK_Div1);% j. o* D! l& o) N
- 7 g) [; d1 Q. E
2 c- W" D. r, ^' j- + T$ M. l) i7 Z4 M4 T! l7 c% {7 ~
- /* Select HSE as system clock source */
3 [/ E) s/ O' ~7 T o5 x# \" R - 9 D; f* f8 u6 b; E" N! d) M0 e( L
- RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
: Y% ?# F% C% }8 Z" q) T
0 u. q( P- o* Q* L- K- . e1 M! C" I. s
5 p# y6 _& A0 s8 l- /* Wait till HSE is used as system clock source */5 h" U. Q5 k+ ~6 [$ I9 b( T
- , J. ?- L! n/ \4 @
- while(RCC_GetSYSCLKSource() != 0x04)/ J* y5 {5 z4 f$ G
, N! L {1 W+ B$ ?9 C; b1 k& D- {$ I% N5 e9 {. s; d1 D* R7 s G4 P
& D# Q x0 l$ E/ @0 H0 V- }6 z$ G# w- {: @4 r# D& k% L
0 e1 [. F6 C" F9 B2 {- }
8 E, o2 |* { x - 8 U9 H0 a! `* `: J6 t U
- XXXXXXXX; //分别为其他外设的时钟配置。
8 D( M4 |* c! V0 ~
; C4 e0 @+ R2 j* c! S% w- XXXXXXXX;
V, k/ S. ~3 T - , B: U' T, }, q; ]
* [. d8 @2 U2 z
) K( I3 \0 C3 R# f- XXXXXXXX;: Q: \1 `+ a; I( v: x
- 7 K. |1 L. |3 S# U' o2 ]# D ^# A
- }
. y) V- q# |9 j" q7 i" V
复制代码 : r- v3 _* ` ]9 y' U
, m% }4 b& |7 A1 L二、关于PLL设置6 X+ G/ B: a( m
7 F# z# f2 {0 i9 a. b) zPLL的设置主要通过函数:void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ, uint32_t PLLR)来实现。
) h$ f( D% O) e0 }( Y
0 e$ G: U$ x; o主要讲一下PLL值的设置与各部分时钟的关系。函数中涉及到6个量的设置,第一个为内部时钟或者外部时钟选择,后面几个为PLL值的设置。7 c% O) e- R) x; X
9 S) u: V( J( } Tl RCC_PLLSource选择:
9 @ O9 k5 j5 z1 W, t$ i! Y8 C5 o& q! h: p- R4 I2 g4 z
RCC_PLLSource_HIS:HIS内部时钟选定,频率为16MHZ
/ J4 o& o$ }% X* X% T$ {& z2 l: e% i
RCC_PLLSource_HSE:HSE外部时钟选定,频率可自选,4MHZ-26MHZ之间,系统默认25MHZ,如需改变,则对stm32f2xx.h中第70行的
, r' T: I% W* U4 A* r( ~, g. ~- D# v% y9 s) }
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
# `8 `8 n( u7 \/ e0 \- H) v! c7 p% G* W& @+ ~
进行修改,改成外部晶振的值。
% k7 R) e+ n/ |9 M: |2 O3 o
1 p" {: E+ ?& \1 V1 hl 通过选择PLLM和PLLN,来计算得到PLLVCO,计算公式如下:# @9 [& N0 A& c
7 \5 j- @. Y, u' `
PLLVCO = (HSE_VALUE / PLL_M) * PLL_N。: w+ Q& [* E( D b4 Y
) x& Y0 a9 K/ N! U4 r
PLL_M可取0-63,PLL_N可取192-432。
! m) b f9 A3 l
4 V4 B! ]% ~' P; \/ c2 n" Vl 通过选择PLLP来选择分频数,以得到系统时钟。计算公式如下:. K T3 L0 Z# K3 A& N5 H; p# m" N
5 f; `/ e- ?( I" d+ ^: w! iSYSCLK = PLLVCO / PLL_P,切记不要超过120MHZ最大频率。4 N, @: ?9 |1 {& s0 p- ]) V
* b6 h4 b& k7 X: F* n( }" o
PLLP可选范围为2,4,6,8。3 G+ b. a5 a! h1 t2 P7 _' Z, y0 \
6 t* T( C6 F9 g6 `! Q( {1 j1 f" ]' |l 通过选择PLLQ来OTGFS, SDIO和RNG的时钟。计算公式如下:
/ t+ T) y- \) X' t0 h# \
! p. u: }7 y/ ^. l% D3 ]Clock = PLLVCO / PLLQ,不能超过48MHZ。- c' j V9 t- z1 c7 p+ w
7 X2 ^) d9 }. C* M( }
PLL_Q可取4-15。
+ F( b- o& F7 B, @% b% [' s! m6 ^$ {# g; [! C5 Q5 b7 Q
l 通过选择PLLR来决定I2S的时钟。计算公式如下:7 z9 x* `7 S7 l2 ^, ]
' i9 _$ G1 _5 C8 vI2SCLK = PLLVCO / PLLR。
: w, N& l( O4 B* f. ^/ w! U6 N# p- X3 Z3 W3 q
PLL_R可取2-7。" D. n. H5 k- q3 d; L3 i
" ]$ a/ |1 u( [+ O; |
- C* C/ C% x" m6 Z1 d
2 F: y2 B; m9 |% X
|