一、系统时钟配置6 O* X( Y* \' S; z5 S! A" M! i
* O# K# Q- e: n' y9 C
STM32有多个时钟源,分别是HSI,HSE,LSE,LSI。1 j* r3 }3 L9 e' s
0 K3 i! S {8 d4 x4 }4 e- @# o' c
HSI振荡器时钟:0 L% t3 w2 g( \$ ?
7 S% M4 \" C! {) c1 n+ N5 C
系统上电默认时钟,内部振荡器8MHZ,可以直接作为系统时钟或在2分频后作为PLL的输入。时钟频率精度较差。+ J9 x, M* x* h. l9 R
+ I. Q. C3 r) b# g' a
HSE振荡器时钟外部:8 z' h' o: Y7 X4 g5 Y6 k8 j& G
4 n# N% ^9 D0 _! v提供非常精确的主时钟,STM32F1系列的板上为8MHZ,STM32F2系列的板上为25MHZ晶振。经过PLL倍频:作为系统时钟。
( J: z% B( F! V* A! C1 j; H. @4 f& w) y: F( d+ X. i
PLL时钟源输入可以是HSI时钟的二分之一,或者HSE时钟。
4 e+ O7 y+ E0 n& ~. R1 H# ]4 O3 P/ i+ w! O% N4 Q! w
LSE时钟:
$ L- ^9 s3 J- \! D2 b# t! e2 X# ?- \3 ~- e& Z$ E5 }9 y+ N
LSE晶体是一个32.867k的低速外部晶体。提供实时时钟。一般专门用于RTC,等到RTC模块时再使用。
2 ]: F% o( j2 P% f7 L5 I. I. s( f4 j7 x* |
LSI时钟(Internal内部):
, j7 @ u: i; \; p! d
2 s+ j! H% M+ e3 ?5 y' RLSI的RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保存运行。为独立看门狗和自动唤醒单元提供时钟。LSI时钟频率大约40KHZ。一般用于IWDGCLK。
+ v6 O' O0 ?, s- U4 C, Y( k( d9 r! k
通常的时钟选择为HSE配合PLL使其工作在72MHZ(STM32F1系列)或者120MHZ(STM32F2系列)。& Z+ i# P- q5 T& g+ }
& Q3 z( a4 U5 D
* l" P3 t5 ~0 S9 F2 u1 C T7 _" W. ]
STM32F1xx系列 * t1 E/ d8 h) G& G6 X! Z$ I
/ b- }# }' D& V# s& ^" I& `
$ r" B7 j- k( {* g- n9 G+ g8 `! a6 K, g* r) \# x: U9 H, }; K+ b
STM32F2XX系列
0 _3 G* S' a: ]( G/ J8 v# b) x& Q! S' L
RCC_DeInit()同SystemInit()的区别仅仅在于SystemInit()多一个SetSysClock()。SystemInit()包含了整个内部时钟到外部时钟的配置,但配置的频率不可调,如需调整频率,可以自己用RCC_DeInit()再配合其他操作进行。1 P- _ m3 q" e9 c3 F
: f9 x+ y5 r+ m1 A4 I: D
配置时钟流程:
/ G |( h8 I) m* k3 Q! b w) S" ?0 T6 N: |+ w7 r
1.将RCC寄存器重新设置为默认值 RCC_DeInit;
, F1 b9 |# Z5 C+ N5 j9 I& \
: ]$ K) P% r+ h7 e1 g1 K2.打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);
6 y/ H, D- O( p
" v8 T7 u4 V; `+ F3.等待外部高速时钟晶振工作 HSEStartUpStatus =RCC_WaitForHSEStartUp();
+ e+ R8 N! y: L6 Y8 L( P3 L" M
4.设置AHB时钟 RCC_HCLKConfig;* |+ e6 g# w j& \( `1 f/ @! h
$ n( j _; [ f: p5.设置高速APB2时钟 RCC_PCLK2Config;. A; m. a6 Y/ t: @
Q: L+ R- |9 D" S7 l6.设置低速速APB1时钟 RCC_PCLK1Config* T5 g* \* j1 s" ?9 `3 b- }; E
$ z, C/ M% X( h; D( K m
7.设置PLL RCC_PLLConfig;9 z7 h& ?3 I5 u* N9 U0 o
" d7 t5 c% Y. _& k1 X& t
8.打开PLL RCC_PLLCmd(ENABLE); _: Z2 A5 z& M6 @3 n! P4 l
6 C' O/ a( X7 t5 d* t( b
9.等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);: ?' D/ f: x% U: N$ f3 ^
1 T! B& `# b" k/ Z
10.设置系统时钟 RCC_SYSCLKConfig;
: U0 V; |! r4 k) I( M7 _7 W( H/ O1 Q, t D
11.判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08);
J* Z! k7 n# d& Q% L, G/ F0 P: `( l6 u9 R( ]
12.打开要使用的外设时钟 - RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd();
1 P6 b- f. W3 q6 h) @
: d/ b: J7 _# L3 y. G- /*******************************************************************************0 R' m/ u7 N8 f: \8 |
~8 l6 p; m9 p, q- * Function Name : RCC_Configuration% ~! j" O% h5 S3 H4 s, k. H
- 6 T3 Q$ I; n8 L I6 N9 I& \
- * Description : Configures the different system clocks.
6 I! A1 y" D7 }# ? - 4 n \; W, u* S
- * Input : None
0 l3 O' s/ c7 o/ F& P+ G, J+ [" D - 4 w0 {. H. g2 m9 z" t" Z
- * Output : None
- B: u$ d! b+ V3 N8 ~1 X# E - ! n+ x5 C! {# P! ^
- * Return : None
, V6 w% ?7 `/ Z$ X" O# a% I) c - ' D+ w* R2 c) \, v3 Z4 {& w( A
- *******************************************************************************/
+ f R. s3 |& W4 m' _7 e5 [
1 z5 z6 e; q/ O) H2 W3 ?- void RCC_Configuration(void)* k* m; Y, Z, n7 l4 R% y$ P
4 ?) Z% F7 O) n' G- {
; q6 r1 s8 i, q7 D! e0 Q - ( m: s+ N5 E5 B' Q$ ^# V. c
- /* RCC system reset(for debug purpose) */
J' C& X9 w7 G3 V$ t" u - / J0 A R" I! F. T w+ r5 n
- RCC_DeInit();
5 J h5 \) v$ H8 p
; L; E k8 a' k! p+ F7 B$ F1 D% g( J
( T& X9 s0 m2 Z4 G
1 b: `7 }" d2 V2 l% h) ]: p- /* Enable HSE */" d% P8 v" B. W& A- s- X
0 `" T9 R0 d$ Y" ]8 W" F- RCC_HSEConfig(RCC_HSE_ON);
( `+ B; k9 M% Y1 [5 y! F - ' O8 b* s3 L5 }# M
) ^8 L$ i; m+ J1 n# g
$ Q# h4 k# E8 V: Q" _- /* Wait till HSE is ready */
8 j0 Y9 p+ x: h* X - * f1 J0 o6 t8 Z, E! r. O6 R" s
- HSEStartUpStatus = RCC_WaitForHSEStartUp();
" n& u8 i% b: W% }# E5 \; @; ]; ? - 1 ?( G! M) j/ Q6 m ?
6 U8 b1 U- ^# q7 |* j- " J3 I: J2 X+ u2 T
- if(HSEStartUpStatus == SUCCESS)
* @4 f* P9 o h2 k! E" P
- F6 k8 F. y1 _8 |% M) ?5 j5 d( G- {
0 |; e( n D2 ^6 |' @, z8 M' s - # |- `* z. O V& _7 J0 |
- /* Enable Prefetch Buffer */
" Q+ I8 B r. y: v/ v D& B0 Z! Q - 5 a5 W2 ^3 h* b" u
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);7 q e T- _" Y. f3 ~$ n4 q
- 6 ^2 y1 [! G0 L+ }+ u. ?
- 0 k8 N+ i1 n) B$ o: g- B7 K3 P
- ; I: t! p) i; m! W
- /* HCLK = SYSCLK */. \% b: g- U- ?8 x) Q/ i; d, c
- 6 r) H: q4 p1 U+ e2 }8 C
- RCC_HCLKConfig(RCC_SYSCLK_Div1);# f8 D4 V H: h4 y( S, G8 y
- 6 U5 V& z4 x$ g x) K
- 4 e8 i% i3 n' r5 {
- ; p2 H) b5 n3 s5 m
- /* PCLK2 = HCLK */
- f( f2 I; G$ j+ w3 H6 a
7 [- s% a. t7 s$ s- RCC_PCLK2Config(RCC_HCLK_Div1); m; ~. S- v6 u4 p9 t* Q8 s/ C
- 8 Z: l4 W1 y( l W3 ^; W
) p# t C7 P5 I* O7 O7 b- 3 J8 O) V( ~% p% V
- /* PCLK1 = HCLK */" i3 L: G; B- {# t8 n. m5 i
- 6 y8 x8 a+ @# M$ c; Z
- RCC_PCLK1Config(RCC_HCLK_Div1);! M8 K8 ~5 u. o. \
+ R- z" w2 n5 y1 s! ^2 U
# n! M* j2 o0 z: _; x$ |! Y4 Y6 ?2 g- 9 f/ t7 {' P; t$ z& R& k; P3 X- d
- /* Select HSE as system clock source */7 G( |% K( e; P6 ?* I. {! E1 y, ~
+ v6 ]$ a# [3 ?- RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
2 K8 l2 U0 l1 b* h& ?, P - ) ^5 l* g) C8 q# K. @. Z
4 o, E1 Y4 U; [- ' R: f+ @& n% E( P
- /* Wait till HSE is used as system clock source */6 Y2 k) j3 F5 C
- * N, Z; x5 Y# ?5 j; @2 G
- while(RCC_GetSYSCLKSource() != 0x04)
$ f& A& N3 b$ C$ d, b4 g5 ], H( G' ^9 @
" E, ~8 W: ?9 _! ^1 W/ u- {
* B3 j/ v6 i# Q a5 k - 8 R! B, P/ N4 F4 k2 n
- }
( I- f& S& _, E# T; D' Q - 3 o# [% P+ ^- R1 S
- }
( K; T) ~: q% T! w- L
$ S0 F3 R" A) w; a8 f0 Q/ X- XXXXXXXX; //分别为其他外设的时钟配置。
. u9 D% r# u; |7 T$ e0 F6 Q6 _
% t! O4 i3 V( q r: @+ s- v7 S- XXXXXXXX;: F% m" ~' r$ ^0 v# T x/ p
- # T P0 O" o2 u& [
- ! H4 v( R( ]$ v6 J0 T
- / `! k4 {$ ~; x \+ y
- XXXXXXXX;
1 ]9 z3 Z H5 J: ]( P - ! C; _' _' m* H O& q0 b
- }
1 Z8 U2 \; f( K8 z- w+ _
复制代码 & }' x3 B2 C, X/ `
( \6 B) c( |. ?% w二、关于PLL设置2 i! M) E% |; h' H" Z) l
1 M' @4 I4 y' @+ }
PLL的设置主要通过函数:void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ, uint32_t PLLR)来实现。, E$ [ ?+ G) N$ d9 y
, J! X7 i8 D( Q/ Y* i: \& |" I4 e
主要讲一下PLL值的设置与各部分时钟的关系。函数中涉及到6个量的设置,第一个为内部时钟或者外部时钟选择,后面几个为PLL值的设置。: R2 T9 v6 }: F% C1 r3 b& r
B$ r: F9 l! |9 p; s$ O6 E+ h" Wl RCC_PLLSource选择:
- z8 r+ `( ]0 D1 n5 ^5 y% A4 ^( V3 n: ~0 q* a( v$ _
RCC_PLLSource_HIS:HIS内部时钟选定,频率为16MHZ# u1 l, \0 f M) T( U6 i7 h8 g
2 V' W. ?* b* _+ B- S6 Y4 I
RCC_PLLSource_HSE:HSE外部时钟选定,频率可自选,4MHZ-26MHZ之间,系统默认25MHZ,如需改变,则对stm32f2xx.h中第70行的
; e D& \% C+ n8 }, u' k/ o5 l* S/ n7 t7 Y
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
$ I: w6 G' O! _- M; g% c& ~5 G2 V; K0 k0 F$ L
进行修改,改成外部晶振的值。
U. f2 D& }1 x: F& {9 |# f: h( t3 q5 f: ~
l 通过选择PLLM和PLLN,来计算得到PLLVCO,计算公式如下:
4 ^/ v8 k4 |- n. \, ]" `% f# x/ h) r% {$ V$ i
PLLVCO = (HSE_VALUE / PLL_M) * PLL_N。
/ N4 Q8 \. y; t5 n, z! b% M/ A. g) L I% }9 Z; F C+ |
PLL_M可取0-63,PLL_N可取192-432。
4 D" m3 d( D3 \, I7 V1 h, X5 K1 C1 O$ w
l 通过选择PLLP来选择分频数,以得到系统时钟。计算公式如下:3 o& `" C4 y3 s: c$ S" F' d0 I2 H
/ X0 E. Y3 G3 B( rSYSCLK = PLLVCO / PLL_P,切记不要超过120MHZ最大频率。
& F) J6 ?1 @4 e8 ^
1 f$ ?- Z& V+ h2 f7 y. }9 o$ |# nPLLP可选范围为2,4,6,8。, q+ ~6 D/ c1 ^3 Z3 d
3 x( B1 Y* m" |1 O, u. il 通过选择PLLQ来OTGFS, SDIO和RNG的时钟。计算公式如下:% N& L; c3 `4 O% q5 o6 X9 Y) [" z
6 m; p- k. R7 r
Clock = PLLVCO / PLLQ,不能超过48MHZ。
) [4 O1 w7 v. h* r
8 X3 T q; a+ {& ?8 M. [PLL_Q可取4-15。
& ~+ ~; v* M. A* Q- ^4 Z; M0 c6 |2 f- b
l 通过选择PLLR来决定I2S的时钟。计算公式如下:
: ~. ~% c2 w) H6 J
9 s) f- p. s4 M/ L, GI2SCLK = PLLVCO / PLLR。- b. i3 j& V. |" j; E
1 }, b$ B1 X' _# p. u+ D
PLL_R可取2-7。, J/ k% H g) x6 W0 A
# T* Q( g/ m* u; o" V
' A2 N9 o! m* }2 H( K! L( l0 E( D% a% v. p6 W
|