本帖最后由 TLLED 于 2018-12-8 14:42 编辑 1 x! o5 O- }. `# d/ H8 Y; U
$ j! F, U4 ?) b9 h) j9 G 通过第16章节 -- RCC-使用HSE/HSI配置时钟 的学习来重新认识系统总线和外设时钟的配置。
0 d0 u1 ^1 _# C4 M8 [
1 t G6 O( k) F7 {% S/ O 一、手册中有关时钟配置的内容
& o, H, o4 T, x* P+ a
9 e* ?7 D J( ]" ~0 A& W7 I! o- }) a
1.1、系统时钟框图:
+ @0 e! w" ` r/ R 里面显示出STM32芯片所有时钟和有关配置的寄存器位
9 J3 X7 m! z8 M0 g. b4 ]5 W% L
1 U. M/ a' @1 t5 n" O3 ~3 g % |+ g) q$ ]* f; z5 \* W
二、系统启动有关时钟配置代码* W9 m c2 i8 [4 r
/ F$ G4 S8 P3 S0 ?" M' V( U
2.1、系统启动分析
0 Y; i0 w. V4 f 上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
6 [; {1 K6 t G! v5 }) G6 ^
5 A! w3 A' L+ f
里面有执行SystemInit系统初始化程序% s$ T6 W; P4 J* F. O! h& q- e. }
. w1 e/ g/ U1 W, |" }! K
; J) @- E& S9 j" u$ u5 m
里面调用SetSysClock函数设置系统时钟
" Y2 J* _1 h5 G$ E+ L* B, b
+ R4 ]/ S b, Z( s6 E) K
SetSysClock函数配置为72MHz后调用SetSysClockTo72函数
+ D$ s- ]8 p) m
9 Y( `1 \: _( Z6 Z
+ s/ D3 e2 n6 p0 I
- J- d ^7 b- K$ @5 ?
4 ]. A, V! X4 O4 |$ d0 F9 \, W 上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。
4 ?2 [/ g4 [0 X( Z: c. u$ j
3 ?* Q4 P& w* c9 S7 N 三、时钟配置实例2 @( J& A9 G6 S$ j
( q1 a( }7 J R3 Q& Q
) J8 y6 w, j$ q! w- ?' u 3.1、配置HSE时钟
7 w! Z. g! d( \) E& q1 ]; W+ i 了解系统时钟配置流程后,来实践使用时钟配置。) b6 X2 N* b4 J5 ?6 T& a
在系统时钟框图中,HSE时钟配置+ D8 `% H' S8 t
( q4 O8 e# ]+ A4 j3 s8 G4 w! h >选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振
% n+ L7 j% ~- T7 u# t" U5 k ~/ ~* }4 J >通过PLLXTPRE来选择HSE时钟不分频还是2分频。8 H6 J/ Z! T; m! h" j6 @8 K
>通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。
/ r+ t& I2 V( \" M >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz
; [! z' R p4 ?0 m3 V >通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。
( g- b4 T! v& Z/ `/ T9 U* O
7 t" q0 S0 v2 z9 l3 `2 K
5 G8 l% `: Y9 } u" Q 3.2、程序源码 S+ a" q! ~4 ?6 t* ]. L% C, R
3.2.1、HSE时钟初始化4 Y' L& m8 N% p" \1 B" Q! y+ x! K
PLL时钟倍频到72MHz b: m; D" r6 Y9 `; y/ J& N; m
- static void HSE_SetSysClock(void)/ V: h( d1 f% ^6 h& C3 r
- {8 A. f& }! R+ D% |) i
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
& m4 S: {1 ~- x5 k7 | -
, n, w' @) e7 K7 {& d* Q! D0 D1 D - RCC_DeInit(); //RCC恢复默认状态
- B% L, G# s, K5 z - RCC_HSEConfig(RCC_HSE_ON); //打开HSE时钟) U( {9 v8 x" o) z) l; W& L! F; n
-
' ]" U( A$ o) N/ k- b! ~7 c - HSEStatus=RCC_WaitForHSEStartUp(); //等待HSE时钟稳定
+ i! J) |2 ?) a8 r
. ]6 k+ o& H9 p: B8 w& J- if (HSEStatus == SUCCESS)# \; f" ^' O$ }1 v# ]; w, b1 R
- {
3 J0 _# _5 Y8 j: Z4 n - /* Enable Prefetch Buffer */
- F" \; z5 I: E8 G - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区
& @/ \, }! U1 O8 z- Q: g2 } - FLASH_SetLatency(FLASH_Latency_2);
& ~. Q' k5 N7 b
}2 ?! v) t! W: v5 ?; V/ m: T- RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB - HCLK=SYSCLK
& i% k. n* C" a, d1 s - RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 -- PCLK1=HCLK/2
% x4 m* C3 R% C - RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 -- PCLK2=HCLK) I$ j4 ~+ z, G; i/ J8 P+ m
$ Y/ `; g" f- w: m- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频
0 u! R& A+ N! m& F, K5 z& o4 J- s - RCC_PLLCmd(ENABLE); //使能PLL% O3 v6 v, n( C
- & O5 `' v4 ^, {0 u5 |- w; V* h
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //等待PLL稳定% ^4 ?. U% [3 q
- {2 b1 X5 h6 _0 \# Y
- }
7 u: B1 e" u3 T' H! _$ a& H* @& a - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //PLL稳定后,时钟切换到SYSCLK" @# \) W/ {: R$ G; p2 s M
- + u" w; }# ^" P! Y) S/ b1 a
-
$ @- |# R) _( |, k! y) @% C! M0 F - while(RCC_GetSYSCLKSource()!=0x08) //读取时钟切换状态位,确保PLLCLK被选为系统时钟
: V- D# [% n* M3 X' R4 O - {+ q6 s4 K* |9 I8 p% f2 S7 z
- }
5 S. U/ }; F3 Q& Z( N5 k$ h( A. S - }
) L, t1 `6 @, u/ T+ B+ |% g9 T - else
" d5 C5 X8 c6 B9 `" V/ Q- c - {# _ o+ I l- \2 n$ X3 |9 \$ P
- }
1 Z0 {3 R) a- G k: u, t7 B - }
复制代码 3.2.2、MCO引脚初始化6 [: l' |- x4 n
- //MCO引脚配置
; k; ]: l. f; I1 _8 c; s' ] - void MCO_GPIO_Config(void)
9 x, j" f1 o! C; A+ Z6 X3 g - {
0 _9 \0 R0 L) H7 Z4 q - GPIO_InitTypeDef GPIO_InitStructure;
: c* j$ J5 }" i c5 M. U- o+ t -
# a0 T3 F% s1 e' K* `1 f6 r - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟( }. V# J( {* s
- , y4 C/ x% O/ U/ S2 H% q6 ~! ?; J
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
5 g4 B5 b* x, ~; b; ?3 f/ N - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + V" t; n. l3 D, {4 O" \
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz4 c/ U- n. c- O- W" h
- GPIO_Init(GPIOA, &GPIO_InitStructure); - |% c* d( z0 c# @
- }
复制代码 3.2.3、LED引脚初始化6 T3 m$ ?, }% C4 m2 x
- g) ~: P$ n6 X+ B- ~
- void LED_GPIO_Config(void)
( }0 A- d& f5 `/ d - {0 P5 |8 f* k$ i& ~
- GPIO_InitTypeDef GPIO_InitStructure;( x, W* s, ?' l% k& i5 g
-
- h) i0 b1 B$ O& t - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟& g( U4 ]5 d5 c: S/ X' P+ H
-
% [, K% x% }- h0 Q" E: L x - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
Y2 X& F r+ x% y+ K - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; / {1 L3 X: C4 R* q7 V
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
( J4 [ M6 v) d4 ^7 U: D - GPIO_Init(GPIOB, &GPIO_InitStructure); 9 g) e$ \+ `4 d
- }
复制代码 3.2.4、主程序/ |1 P" `5 t+ m9 S! z" J' I
- int main(void)
, E2 r4 o: z. k - {; u9 G1 F+ Y. \) O5 K0 Y9 o
- uint32_t i;
8 p. |9 R* u+ e, T. V4 Q5 N. W - HSE_SetSysClock();& J' P. @1 j6 q7 \! q, n; `# L2 C/ P
- MCO_GPIO_Config();3 b) I4 {8 `$ Y: S2 C9 S" C
- RCC_MCOConfig(RCC_MCO_SYSCLK); ! H) g H1 y5 f3 V; b9 `
- LED_GPIO_Config();
3 B( A( m8 L! L" J - while (1)
3 R, i6 z& V5 g0 _; c) C - {: Q$ c, m5 k# d3 ?) g! d/ I
- 9 O5 S2 u: ]5 k' D, d2 _; T
- for(i=0;i<0xffff;i++);
) K) j5 Z1 F$ G2 S2 H, B - GPIO_SetBits(GPIOB, GPIO_Pin_9);. s1 L- S; J7 S$ z
- for(i=0;i<0xffff;i++);
' e( m8 f9 h# b( B$ z1 |2 B - GPIO_ResetBits(GPIOB, GPIO_Pin_9);: W$ X0 R/ W: t+ W: w% B5 c
- }
, M0 T* p# A |7 Y$ s - }
复制代码
" {+ s( i$ x$ x) O 四、程序执行结果
4 m$ h4 s) G- x, z( k3 e- v& v9 @1 { Q6 y
& ~. D# z- N0 _* h 4.1、PLL时钟设置为72MHz,倍频系数设置为9
/ K8 M. C1 [* N% \) a6 A& C RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频0 x; G9 N" ?- H/ q g; h
4.1.1、MCO输出时钟频率72M, c3 c" ^9 u7 o. @$ b
9 t8 L: h6 o, F5 Y- T" \0 t9 O 4.1.2、LED引脚输出
, r2 B- u$ l" e+ l% D% t( P v
# q4 O- p0 W6 j4 R% O- [
4 W! ?0 ?! L/ z2 W3 V# Q 4.2、PLL时钟设置为56MHz,倍频系数设置为7 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //PLL倍频, T3 K9 q% [8 V1 B1 U3 N2 ?& I- j
4.2.1、MCO输出时钟频率56M7 ]4 H9 Y$ n- Z/ n) I# ^
2 A8 P! L V2 Q- d
4.2.2、LED引脚输出
0 H; }- a( H: ]2 J2 p
3 g. z5 y: d% W3 h3 X+ @! G
LED输出宽度比72M时钟时,宽度变宽
* v" d" n' \6 S" @- N 4.3、PLL时钟设置为88MHz,倍频系数设置为11 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11); //PLL倍频
" [# f! }3 G; [; j. j- G3 i' f, p 4.3.1、MCO输出时钟频率88M
) w/ W- _( F+ L% _- G
0 _. n* A$ I8 h$ t. A/ v& I' F 4.3.2、LED引脚输出
/ ~0 ^( n* v9 v9 P; k
. p" Z {8 W( N1 K7 u LED输出宽度比72M时钟时,宽度变窄5 G1 m* j4 m% A: M2 Y ?
& K d) O6 K2 W9 M+ x1 @
五、结论: R1 b: m. P$ d* T/ V' V3 e6 M
% ~. O+ Y: G. h# r: N: `, L, |
0 }& o0 y2 N4 [ u: z 使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。, r8 ^! M, _( y; K
8 d3 {5 j) J2 I9 J, w9 J {9 H% R' |
; b7 Y- \; `7 Y" h; w+ T
Z4 h( V1 R; l' \/ N* g9 {6 _
; |1 D) V, p, Q& o) b! B) v) E$ t; U8 J
# c M9 B& a0 s0 M! w$ `
?2 ?4 K6 J8 w3 G" A |
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));4 Q& m0 U0 e4 k8 j
这句话是把第16-21位清零
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。) E% `8 Z5 L1 f9 y. P9 l
0:HSI振荡器时钟经2分频后作为PLL输入时钟8 c9 K* k3 X8 b6 Z. l2 e
1:HSE时钟作为PLL输入时钟。
以上是手册里说的
这句话是不是把相应的位置1 这样就能配置了