本帖最后由 TLLED 于 2018-12-8 14:42 编辑
- T+ c/ Y& M; B6 y$ t1 m0 ^: A
7 i/ E7 Q* z4 a 通过第16章节 -- RCC-使用HSE/HSI配置时钟 的学习来重新认识系统总线和外设时钟的配置。 # L1 X( t6 C" A2 f- }9 y R) b& o
+ F2 J$ w( ~: A9 s" n e 一、手册中有关时钟配置的内容; K) V8 o* E9 d7 L
/ g$ }( o& i4 L9 Z* u }4 _
7 W: Y ]6 }2 `3 V3 f 1.1、系统时钟框图: + f1 K. y$ G. O5 D R
里面显示出STM32芯片所有时钟和有关配置的寄存器位
( s4 U8 V4 ]. Z. n
- Q( B) M9 D" z0 @ n5 d4 p 9 l2 A6 |+ V- O: u9 n$ e% X
二、系统启动有关时钟配置代码
* }8 h- X6 I" P' o+ R# j2 J8 r. V, a7 k; Z0 V' w% k2 }3 D
2.1、系统启动分析3 S, o& ~% k) R* s! F3 F
上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
8 M: v8 _2 p. y2 y8 r" @1 K- f8 \; J
3 ?' S `7 V0 s4 H! J
里面有执行SystemInit系统初始化程序
?# f* |/ ~! g+ A
: q! E [9 o) }
" S0 }' p9 y: `6 T$ n/ E: E
里面调用SetSysClock函数设置系统时钟3 |' c: Y9 |: T* A2 @
" x# g2 k4 q' J0 R
SetSysClock函数配置为72MHz后调用SetSysClockTo72函数, B* [4 o4 g& V# k/ D% t
' @% ]9 }. ^- v- b1 k
* Z0 h& V: F% l8 m' v. S+ z) a( \
/ c. j5 T$ p% V F3 |
' k: b$ n4 l7 N 上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。8 W5 r# h- S7 |8 Z! k9 t
0 o) {' {' a: H4 p8 D+ |+ [
三、时钟配置实例
, w' D1 ]$ {! _# t4 Y: ?$ k' ]
1 T) ^% r3 k5 f! j. K
3.1、配置HSE时钟
3 U1 Q; s* ? i' [- d$ `& ]$ u 了解系统时钟配置流程后,来实践使用时钟配置。* f+ ?7 z, m( z( c
在系统时钟框图中,HSE时钟配置
) l7 v$ M, Z5 s L0 t, L
, \* |: B# ^* P6 Z5 Q: d
>选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振 R# D& U$ r+ B7 I# U: ?, g
>通过PLLXTPRE来选择HSE时钟不分频还是2分频。4 Y8 k9 Z: G& a- m1 b8 J! n9 J
>通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。
* c9 i, z6 }% q; `$ T" a/ o >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz A. l6 C& a+ Z
>通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。" [5 O+ u1 i- }3 i0 f/ U) X/ J9 O8 @
5 r5 _' v2 _6 Q: w6 y) ]3 O! Z0 R0 S8 ~
3.2、程序源码
% f. b8 T; i; v0 m f) ^$ S 3.2.1、HSE时钟初始化4 q5 X+ U2 ?3 E+ ~2 C# J+ l$ b
PLL时钟倍频到72MHz
* v. g6 s+ n/ ^. Q6 r7 v% M - static void HSE_SetSysClock(void)
7 ?- K7 c6 w+ D6 q - {. M6 Q, w" }$ ~1 B$ x' m# T9 b
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;; M( E. r* B8 ~! H5 E- L
-
$ G- Q8 l9 o; t6 I- z( F0 m - RCC_DeInit(); //RCC恢复默认状态 " S( D) [2 g: U8 K ?
- RCC_HSEConfig(RCC_HSE_ON); //打开HSE时钟
$ W' g+ S" ]$ e* y5 h -
6 M; |4 j! `( v. |- a1 S - HSEStatus=RCC_WaitForHSEStartUp(); //等待HSE时钟稳定) U0 ?( i* n+ _4 i6 |7 m
: s0 |* U) S+ h' _6 v" a- q% D3 J- if (HSEStatus == SUCCESS)0 Q: F! ?1 s+ d0 L* Y0 X
- {/ a0 B9 ~5 `1 y( b
- /* Enable Prefetch Buffer */
+ I. C1 H' y9 S6 b$ z4 N - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区
! b8 B& @! T' ?7 U: R0 l* b - FLASH_SetLatency(FLASH_Latency_2); % L! N8 _/ ]8 y' B" x' l& w
, V, \1 B' t0 ^( @# L$ p/ \2 f- RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB - HCLK=SYSCLK
7 x7 L$ {' n$ m8 u - RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 -- PCLK1=HCLK/2
$ [7 H: c& l6 L# w: w0 i, B9 J - RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 -- PCLK2=HCLK
& `- t3 e1 e- f5 F; D8 ?- o
8 c$ t, I/ e: q- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频- g; H/ s: F: B* W4 a T8 u( M1 {7 O
- RCC_PLLCmd(ENABLE); //使能PLL! R* ~+ ?- j( S8 y* v. O0 e
- ( W( [+ E& @# E' p) U4 `4 u- w/ _$ v
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //等待PLL稳定# z! l* v3 e0 M T9 o% R" }
- {: ~1 F) `( o3 X$ H1 I
- }
+ O [) M( c/ k9 \3 p - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //PLL稳定后,时钟切换到SYSCLK4 _2 q9 Q L E
- - k6 Q' [2 }$ ]; q, y* Y
- 6 W; y. u S n+ _; m+ t0 u4 F
- while(RCC_GetSYSCLKSource()!=0x08) //读取时钟切换状态位,确保PLLCLK被选为系统时钟: D1 _7 R) d( x* u: D+ \
- {! D% a0 m3 t. v/ E+ ~' X) s7 y. d
- }. E: \6 ` K( ^' q0 e0 r6 W
- }1 j- B( Q4 l, \6 M2 k+ u
- else% ^( f8 ?( c4 I/ R# |# \
- {0 d) g- y) H1 k
- }' j. G; S v9 v3 ~, R" Y
- }
复制代码 3.2.2、MCO引脚初始化
' S5 \) P# q8 i2 F) J4 Q- //MCO引脚配置
7 H8 m: x* r: h1 r - void MCO_GPIO_Config(void)
, _+ p8 p/ o' v( W - {
2 j3 H& U9 }/ g - GPIO_InitTypeDef GPIO_InitStructure;2 W* _! I: R) }9 L
-
9 R( j$ F2 E7 r0 f' l% P3 x8 w - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟' j* A# [/ w/ j y# G* T- H
-
7 D3 ^% {8 }; P& A8 I" C/ r/ G - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
/ j! W; V& ^' s. } - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
1 x6 U; c4 Q! g& N7 ` - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz' e2 g2 V+ r8 L: G4 `
- GPIO_Init(GPIOA, &GPIO_InitStructure);
4 c$ x) L, c# n* U# P$ } - }
复制代码 3.2.3、LED引脚初始化9 h2 M; _8 C4 R" j. _7 y# t: f
3 `, G6 n# V3 T, Z0 N8 z- void LED_GPIO_Config(void)
8 d0 Z- U5 d! V$ B' w5 f/ g# A - {9 F" z# l2 N' p- W1 G
- GPIO_InitTypeDef GPIO_InitStructure;7 e3 ~$ M! ?0 g$ t$ I
- : B* z% y F: P2 u
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟, j; x1 q6 T+ w. y; j! x& m
- , W8 v7 c$ i0 ~
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
* u r6 j8 E2 g# P) n8 { - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; / U" e0 Q5 Z2 Q, M
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz2 i! K9 v! o8 Y# S% X, Z
- GPIO_Init(GPIOB, &GPIO_InitStructure);
0 h5 |* N+ i- j0 j/ s# |+ r - }
复制代码 3.2.4、主程序
" j+ |5 `6 H0 r* r3 E! E- int main(void)
; e6 b; R+ O' V& F9 R- }$ O+ N - {: {3 K! t3 _# E$ n! @& L" A
- uint32_t i;
" O" U3 ^- X! Z" W - HSE_SetSysClock();3 V+ B+ c( x; m; C/ W3 w% z$ @; M
- MCO_GPIO_Config();
8 S/ Z' I* t( p5 I& t) u) \5 v - RCC_MCOConfig(RCC_MCO_SYSCLK);
) ~- C+ g. C1 t0 l$ i - LED_GPIO_Config(); 5 D8 y. l+ _6 H/ W3 m6 j7 |- l! S
- while (1), e$ g8 Q& `# x) h) ?
- {" _: q9 A& x8 X- k# c
-
6 n$ Z0 \! f/ n9 m4 H. O - for(i=0;i<0xffff;i++);" E Z c; Y t) V. x" R
- GPIO_SetBits(GPIOB, GPIO_Pin_9);
; w( K5 ?* k' } - for(i=0;i<0xffff;i++);% o9 t# S$ K; f- v, I8 w* i
- GPIO_ResetBits(GPIOB, GPIO_Pin_9);6 B! s5 r5 _, O. u% {- I' z
- }. a3 v' Z8 s. ~9 P9 _
- }
复制代码 ! a( O% T3 X1 Q2 T+ ^ u% S1 k
四、程序执行结果
) s5 [- k+ `% T2 d3 S* l6 {+ I, j- w& ~3 Y2 \. ]* z
+ n6 l! |( {2 d# r7 G" L$ s
4.1、PLL时钟设置为72MHz,倍频系数设置为9
6 Z% \; m! o0 h3 h RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频# P* [4 x \0 S5 M% O8 I& q) c
4.1.1、MCO输出时钟频率72M# { [$ r4 a: K4 x4 [+ R5 f( f
7 {. u! S/ F. P; t& W- _) @9 ` 4.1.2、LED引脚输出7 z8 X; P, \6 Y" \
) K' L7 b6 z6 s- ~: A$ V* c
3 Y. d5 A( }+ p9 O ^# I 4.2、PLL时钟设置为56MHz,倍频系数设置为7 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //PLL倍频
3 g& q' ~8 H9 M q& C1 @4 z 4.2.1、MCO输出时钟频率56M
- v8 p3 M9 \# H& O) T% U5 W' U
4 _: G9 s" n! t8 r# O
4.2.2、LED引脚输出
$ e) v4 |4 }0 r) Q2 Z- ~
$ [* p, W+ _0 s+ O! ~ LED输出宽度比72M时钟时,宽度变宽
" X# p' o, ]" |6 f+ h 4.3、PLL时钟设置为88MHz,倍频系数设置为11 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11); //PLL倍频) e$ o; y' p# G4 a& Q+ z- Q
4.3.1、MCO输出时钟频率88M
* ^8 Y# P1 k( b% |2 x$ Y
! T' g7 b( |! t( E- ^9 f2 y
4.3.2、LED引脚输出, k$ h/ o4 ]* i# z, r( P) b n% s, d
) F9 l1 ~4 z" r# X6 E) V
LED输出宽度比72M时钟时,宽度变窄3 e! i* W# r. R: v( L3 h7 j2 V
6 X5 G, D: [6 _/ R
五、结论3 b& v; O" L9 }! x' o7 E1 ^
. r8 u; u* i a5 A# {
: y! V( S( B- F" w6 ^; Z- L 使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。
9 c5 u! h) A7 K4 c" r
+ u4 z o3 P6 o9 d9 i" Q" S- B2 x0 m7 L- }, z! |
/ v7 k$ t2 \7 W( A* u2 ^9 @& p% {# X" g9 I" }6 M
v9 e0 F4 n2 R- m
2 I; k: l6 Q: q+ l/ }
* T, _% M) e$ V+ q# N9 ^+ |
9 J- P8 B' L$ q' H9 i |
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));) O* I5 R: s* H2 ?/ d/ Z& o
这句话是把第16-21位清零
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。% c. w3 A" o. m/ u7 [
0:HSI振荡器时钟经2分频后作为PLL输入时钟6 g+ l/ C f! \1 T2 t
1:HSE时钟作为PLL输入时钟。
以上是手册里说的
这句话是不是把相应的位置1 这样就能配置了