本帖最后由 TLLED 于 2018-12-8 14:42 编辑
) R, f/ M- k6 `8 @1 ?6 k' r* T
$ W+ l9 b( @/ v& W! Y% I( Y 通过第16章节 -- RCC-使用HSE/HSI配置时钟 的学习来重新认识系统总线和外设时钟的配置。
. m/ l* d1 M8 e! A7 c- c8 D
' \% a: y0 F1 W+ b: d 一、手册中有关时钟配置的内容: a: z8 |" x( Q5 X% P
- _' k- ~9 U* X" ?# N9 \# `4 {+ ]6 w; `$ M
1.1、系统时钟框图:
: y4 {8 T& l" v. n3 |6 U/ r, { 里面显示出STM32芯片所有时钟和有关配置的寄存器位
0 }. a0 f; ~! |" n
7 H0 c% U& N! \
- d+ ~' O+ d. H' g+ e 二、系统启动有关时钟配置代码8 V8 t6 W+ s6 V X) ]
1 S9 @0 C2 f6 A! C/ p4 h' Z
2.1、系统启动分析
- b. T4 i5 k; c 上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
G/ j2 k) J; W9 z! p
2 E8 t0 ~1 C1 ~8 S {+ Z9 y 里面有执行SystemInit系统初始化程序. V2 n* J+ u# }6 \/ F3 [# O8 F
0 ~; O( d/ G; m% `" N1 m' S& x4 x: ?# i7 H
* C+ w9 b' K; A* B# P' f! T
里面调用SetSysClock函数设置系统时钟
: i+ F3 t- b) x# E5 _( R4 y
0 H2 [( N6 v8 H SetSysClock函数配置为72MHz后调用SetSysClockTo72函数# M$ `8 E) F/ E/ `& A0 T
% E5 x8 ?8 _+ B, d) P
2 G2 ?' |9 Z& @2 ]; Z7 C- W4 f
|* m( F. @+ e& i
* t, E7 o, I2 T# @1 D/ ~* M
上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。1 y) |8 K: r- {. Z
: E, m& f3 o" k( p! m& o# G
三、时钟配置实例
" s0 _% E6 N% r3 j8 s
) B' P- y- G! ?/ c0 j5 S0 l% U/ e5 Y. S' R& o) T5 n9 A" x2 A
3.1、配置HSE时钟
$ \1 X3 W- |, M" r$ h0 v9 N 了解系统时钟配置流程后,来实践使用时钟配置。
9 [- ?2 A, e c" b7 C9 i 在系统时钟框图中,HSE时钟配置/ b9 X2 W2 B2 G& e& E1 c
$ U+ ~0 J! H M
>选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振
5 Q5 F% {( A( Y >通过PLLXTPRE来选择HSE时钟不分频还是2分频。0 ^3 A8 ~8 l% T* y1 [& m4 G
>通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。
! I& J6 A$ r6 V; R7 ], D$ G& E4 } >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz
2 d: O" {' n) I6 V# I1 ?! O >通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。
: |- P! s7 |+ A7 `0 Y
3 e# w4 q1 z3 G5 X. Y" `$ G0 K- I* v+ ~4 l! @/ O" [2 a% ]
3.2、程序源码
2 [6 L9 {. A4 s; L5 N9 F 3.2.1、HSE时钟初始化7 H l; a, i- h/ {7 H
PLL时钟倍频到72MHz( G0 e9 l3 c" x. k
- static void HSE_SetSysClock(void)+ P5 `2 k, Z' x/ T8 G' ?
- {
" H7 j) I3 u4 \ - __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
9 N9 U1 l4 u. h+ G - 6 s! t: Q$ U& \* g$ H- D, W
- RCC_DeInit(); //RCC恢复默认状态
4 l; x. B+ ?& q8 i - RCC_HSEConfig(RCC_HSE_ON); //打开HSE时钟; h5 R5 a( |# P3 c% H; C; C
-
i; a8 }" Y2 @ - HSEStatus=RCC_WaitForHSEStartUp(); //等待HSE时钟稳定- d o. A8 @! y N; y
- " d4 T" C! _5 i) p: O4 @ y0 i- e
- if (HSEStatus == SUCCESS)
; i* S. C L4 T$ o7 j8 Q% B4 _ - {1 E% [9 S5 R. K! X8 s; o& _
- /* Enable Prefetch Buffer */
' V" n& }# m& @! j# S, h - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区- w( k, P- |2 C' ~* k9 k% r
- FLASH_SetLatency(FLASH_Latency_2);
9 e) I; x7 G9 k5 q7 M, Q - 8 e* h/ B6 r, @2 h" D
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB - HCLK=SYSCLK
, H9 i1 S& O1 y* h7 j$ C E8 r - RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 -- PCLK1=HCLK/2
/ R* V8 F& z9 Y! M4 p$ U+ m; R - RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 -- PCLK2=HCLK
: G* c& x2 v$ J, z' J0 C - ' j- l+ N( d/ I+ s- l9 \: ~8 A: q
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频8 R0 m0 H3 I7 ?2 D; C8 t
- RCC_PLLCmd(ENABLE); //使能PLL( v4 l' E2 b7 N L" m- i. v
- * F: @' R; p' E: ~! F$ n; `7 ]
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //等待PLL稳定1 u1 E# t6 x4 T5 y
- {& p ~5 d8 X" C' i
- }
; x2 z5 R/ R7 [+ w7 ]0 ]& J - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //PLL稳定后,时钟切换到SYSCLK
3 p3 k+ _, X8 r5 ]/ B2 O - ( `+ Y; @: f% {* g$ u5 r, Q
-
5 T4 [7 u" C0 ]4 _ - while(RCC_GetSYSCLKSource()!=0x08) //读取时钟切换状态位,确保PLLCLK被选为系统时钟
( z/ i& P8 O% [4 F4 c - {1 H) a" J& k2 @9 u0 T
- }
2 Y5 n. v6 _, R. y3 v - }
8 Z7 g+ v. b! B9 Y# R - else
* G4 t+ B: {6 }) z0 n8 D - {
* f: @. U, Q! N; E+ d0 ` - }# o9 w4 h2 P4 p% K; A r7 K
- }
复制代码 3.2.2、MCO引脚初始化' k( K% w" y/ ?& F# h1 L- U
- //MCO引脚配置; I* H$ P# z P2 j) Y
- void MCO_GPIO_Config(void)
6 f. y. N; a" f, k4 u; x2 g) v - {5 c) E! m+ w0 d9 T2 s
- GPIO_InitTypeDef GPIO_InitStructure;
/ F1 y& e+ e# o -
4 Q& F1 r- z( k7 B9 n - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
7 i; a( x6 ^% |2 Q - , W/ h8 j* c+ J% v0 F6 X
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
! `6 p |8 u8 k- u2 f; x& } - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - e, E( D5 ^ B Q
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
9 q; x. @% ]. F# d$ e" K; ] - GPIO_Init(GPIOA, &GPIO_InitStructure); ( @% y2 r3 J5 z S4 k( J
- }
复制代码 3.2.3、LED引脚初始化; n4 i% e( o" D" Q
- ?: e) J3 b0 U- void LED_GPIO_Config(void)' k9 I5 g& y, \7 g
- {
5 k5 E. \+ B( W0 ]4 h - GPIO_InitTypeDef GPIO_InitStructure;% ~5 h; ^) [ v9 R, E) e
-
! }$ {) U6 ?" { L5 Q$ l/ Q9 _ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟7 M1 r/ P! ?0 [/ F W0 g i% f
- " J& T! j) A3 N5 b9 z* S/ v
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
" p& l/ O6 H& { - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
: }: L& U# ?- ~* u) g$ I - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz% ~6 k+ Y- @& M1 p) F8 z
- GPIO_Init(GPIOB, &GPIO_InitStructure);
( Y. G# ]* Y& {5 N) A8 ] - }
复制代码 3.2.4、主程序
1 Z% s F# C; @4 u8 W& _) I& V' {; i- int main(void)
( o' o! i# K3 ~* Z' R, Z2 t - {
% v5 k- O% O, } - uint32_t i;
' }( q; b' m5 P) k- \% | - HSE_SetSysClock();
7 S3 T" `! \3 v: {8 Q5 C' f - MCO_GPIO_Config();
. p7 J0 N& F% ` - RCC_MCOConfig(RCC_MCO_SYSCLK); 9 H; x9 Y1 ]1 Y" J& b8 f
- LED_GPIO_Config();
; r ?" G% F" Y$ B1 Y, O - while (1)
: B; W* ]3 C0 P. l- M+ x' B - {9 l# Z2 B3 A, }8 g$ C
-
' ~. Q! R9 V! S - for(i=0;i<0xffff;i++);
1 S/ I' ]8 a4 g4 L3 L" S5 O' n6 s - GPIO_SetBits(GPIOB, GPIO_Pin_9);7 l4 w& U% S3 c3 n
- for(i=0;i<0xffff;i++);
) |8 W1 u: g9 C# L: ~+ O - GPIO_ResetBits(GPIOB, GPIO_Pin_9);
+ ~/ T, O* h) V# s - }
# O% e7 p& L7 Q" q, w* Q/ r' H9 h$ y* O - }
复制代码
2 I: ]% B) i* R, m3 n- ?! J% \ 四、程序执行结果1 ?7 ?! _5 J: A. C9 ~
. {; C; q! K& S: ]$ d: K0 L" k7 k: M0 w, z& J7 R# T
4.1、PLL时钟设置为72MHz,倍频系数设置为9
, l8 y" `( C' x6 B5 o( W$ n RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频5 F+ b* ~: x( U
4.1.1、MCO输出时钟频率72M
: C& M4 |. A1 N1 w1 f
# Z9 H( s* M% \9 d* L
4.1.2、LED引脚输出
; g+ W: I/ R2 Z0 |# v5 k* U5 v" b
5 c; D& {7 W& ^% p+ m/ @
" X; r, r8 i4 z( d$ J; s
4.2、PLL时钟设置为56MHz,倍频系数设置为7 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //PLL倍频
1 j2 e6 ?' @5 U0 n t+ P u 4.2.1、MCO输出时钟频率56M
3 [$ a$ e; ~( s& u& v
8 Z# b. I- b# Q: G0 x e. G
4.2.2、LED引脚输出( a5 ]+ w; f/ Y
|5 _7 S8 j) k+ i* O' S/ q
LED输出宽度比72M时钟时,宽度变宽1 W+ X; i7 |" s
4.3、PLL时钟设置为88MHz,倍频系数设置为11 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11); //PLL倍频
* Y! w$ G* W/ @& x2 G 4.3.1、MCO输出时钟频率88M( u6 c5 P8 \7 x+ x& D- Y5 P7 H
1 R/ o/ @2 A# O. ]- v/ C& @
4.3.2、LED引脚输出
. k9 {$ ?$ | L- B
+ f. @& n; w/ h3 R LED输出宽度比72M时钟时,宽度变窄
0 ~/ P T' V0 [0 B1 { i$ H6 z- z* H2 G
五、结论3 n, r3 E" Z9 Q2 B4 Z5 {
% d4 m- J. H4 E, E3 W& K" }' j: Z
0 M) Z9 N6 h5 r7 k9 U" K9 ] 使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。
+ f6 A! G4 \% `) Q! U4 @& j
$ k3 O& y. ^4 C e* U: t5 y8 Z( T
, ?7 K* M _' W% ^1 X% l3 f) q, {* j' f; g, T; x; \4 k( t
2 o' m# S2 Q9 |- Q3 g9 z' {+ m; V( |; H) t r
9 ^9 @& |, i8 Z6 t( M- g
: R9 F6 c- G4 G/ G6 a( Z
( T* \$ u6 I* W( S; ~! { E+ C6 o |
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
这句话是把第16-21位清零
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。, l3 p5 {0 G% _
0:HSI振荡器时钟经2分频后作为PLL输入时钟
1:HSE时钟作为PLL输入时钟。2 v# U: O) C; Q: k( w+ K+ g
以上是手册里说的
这句话是不是把相应的位置1 这样就能配置了