本帖最后由 TLLED 于 2018-12-8 14:42 编辑 0 G; e" y9 ]! I! P" u
! }9 s: Z7 a! [$ Q6 z, A
通过第16章节 -- RCC-使用HSE/HSI配置时钟 的学习来重新认识系统总线和外设时钟的配置。 0 y: E, R& ?" R9 K5 p9 Y0 m; g
$ D4 L6 F0 ]. h* l 一、手册中有关时钟配置的内容- {8 B( L: j( R5 { ^$ b
1 W# @# N0 z( p/ Z6 m) L% ~; Y) R
/ B! {5 E" @( e/ I7 _2 _) [ 1.1、系统时钟框图:
5 ~: ^; U4 z# M9 l* { 里面显示出STM32芯片所有时钟和有关配置的寄存器位
, n# v8 |2 U& u, @/ E: T* F
' E# T( Z5 [% Q9 ]2 A, X8 I
$ S) l7 p7 z0 @2 _8 J. z4 ]" X 二、系统启动有关时钟配置代码
! V3 W: m0 j1 n' W; M
, r: Q% I3 |; x7 J0 w 2.1、系统启动分析: q$ B* @ F a5 `" m
上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
: r) X, S( v# X- Q5 U5 N/ D
, l( s$ |. e/ v5 m' u" O- U
里面有执行SystemInit系统初始化程序, z9 G6 t% o) N/ Y
- t# d, k! d& G1 p# O
+ {* w8 [: e$ E9 S
里面调用SetSysClock函数设置系统时钟) `5 o( {* b( X$ J/ N( h
- K* e% ~9 W i H2 U
SetSysClock函数配置为72MHz后调用SetSysClockTo72函数5 t+ T9 i. t& c7 [5 H9 }
# D! v. h0 f) D% Z: K$ y' P4 }
$ X. ]2 H/ [, u) Y: d8 J" C
p6 C4 `3 ^$ ^1 g
. i% w% c# w: b
上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。
* ?. q8 @& W/ q! j3 c: T0 ^$ O8 H B
2 t+ N8 N3 S( x 三、时钟配置实例: f1 w. b4 ~$ G1 s8 h. C
& O2 Y& ?( _( f5 j, c3 \! q
. E. z$ N' w+ C( e
3.1、配置HSE时钟
7 u6 O3 p4 |6 N, v! l" M% e 了解系统时钟配置流程后,来实践使用时钟配置。0 a$ A' z0 t* G. b1 Z9 x$ i3 y2 O
在系统时钟框图中,HSE时钟配置, i& P# z6 @5 R8 S' i T1 L
7 X6 K: N- ], ?$ m4 K
>选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振# Q1 ~( H" y+ l) G5 j
>通过PLLXTPRE来选择HSE时钟不分频还是2分频。
5 i' K3 [, S- s3 {# W5 E* ]3 J >通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。+ |3 [/ o% `: j- L4 {+ i& w& K
>通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz; d. Z, g2 I& K, L/ E
>通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。9 @. P; _) q( s5 q# _) U3 X
; j* h+ H8 @. J' M. s/ Y# v# Z. Z M6 ?# N
3.2、程序源码 E$ g- t- H U/ H5 a; _ t
3.2.1、HSE时钟初始化# k" j: q$ a: C' G2 ^# N
PLL时钟倍频到72MHz
a3 f. f- l8 }. O - static void HSE_SetSysClock(void)' a2 Q$ U$ B) }, C$ e k
- {6 G% A% c. `! e6 w1 ^+ y
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
. ~" c7 M+ n% y+ j* j# _ - 8 f7 u! J( N1 I: F& ]- y
- RCC_DeInit(); //RCC恢复默认状态 O; ~. R# l/ {3 h8 c' ]8 P6 v: Y
- RCC_HSEConfig(RCC_HSE_ON); //打开HSE时钟
# j9 V! n" J, o4 f7 w - $ a/ z" N9 H' C$ y/ O2 ^- t
- HSEStatus=RCC_WaitForHSEStartUp(); //等待HSE时钟稳定
8 j" E: D; x# D3 ~ - . l9 J1 r B4 e: _- E) q
- if (HSEStatus == SUCCESS)
% l: w; n% k, {3 N& K5 I- A/ i4 k R - {7 m- Z1 j; b+ g; A
- /* Enable Prefetch Buffer */3 X2 p6 h) N$ D6 t
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区: O: A0 s; {; q0 e; `( g
- FLASH_SetLatency(FLASH_Latency_2);
- M, W+ e- P; \1 Y) v; S
\6 `4 e0 t1 S$ `4 k3 d2 q' Q- RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB - HCLK=SYSCLK' v. `0 w& u6 t: |. y
- RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 -- PCLK1=HCLK/2
" p% s2 l2 ^( x - RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 -- PCLK2=HCLK
8 N3 h4 z' a5 u3 |% \; ~% e
$ k6 H2 x1 F j' @+ s- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频
4 I( }/ C' J7 A" ^9 s: h - RCC_PLLCmd(ENABLE); //使能PLL4 L o8 Z7 O* B0 E' M- J
- 3 k! [/ ?1 D5 f
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //等待PLL稳定
8 f, _3 w4 J3 {$ X0 u( h0 S - {2 k/ Y# G' H4 c6 M: ~* g7 d
- }. I( D# o# S9 g0 @* ?
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //PLL稳定后,时钟切换到SYSCLK& Y5 k6 o' m, G. e
- 1 u( V+ q1 ^2 e9 p
-
9 o) l7 |- K- U/ r/ ^ - while(RCC_GetSYSCLKSource()!=0x08) //读取时钟切换状态位,确保PLLCLK被选为系统时钟
. h: h, ^! N3 G* x - {: |" x: n0 b5 l W
- }3 v0 ?! g {$ V" d
- }8 c {+ p/ z1 w, Z' j4 N
- else
; B( a; j) X' T& r# B: M - {
" w3 w! W' U1 C4 i; B! L. S - }
5 R' p8 l; \& S+ C7 b* h - }
复制代码 3.2.2、MCO引脚初始化5 i& f: Y4 n: W7 ^3 @0 B& d
- //MCO引脚配置
. l8 S/ v0 F V - void MCO_GPIO_Config(void); [; Q/ y! T X/ \5 E
- {8 Z- w7 t2 `+ ?, L: ~, F5 w( b6 V
- GPIO_InitTypeDef GPIO_InitStructure;
) e) m% N/ z T- M - ( @ v1 \* D8 |+ V% [1 k' S
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟; N1 m- i4 w1 G% R- N( v
- 6 X% I: z. L: z; m, l* ?. Z/ Y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 8 Y y( J& L. X' p1 {7 D' X
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
% w, {& o8 p/ Q: f6 R; J - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
; D0 F" }* } d1 S9 r - GPIO_Init(GPIOA, &GPIO_InitStructure);
3 u0 r+ r' q. ?0 m2 S$ h' f - }
复制代码 3.2.3、LED引脚初始化
! z* j0 i+ I$ k1 i- 4 L% K: p7 c6 i1 m5 a
- void LED_GPIO_Config(void)1 m3 n- G$ B, X5 a
- {; I$ F6 p! }; q
- GPIO_InitTypeDef GPIO_InitStructure;
7 {$ p$ G# G- ?; J- L3 v& y/ x - 7 X: E. M9 m# ]* _
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟
' a3 N5 x4 J+ i -
6 _7 R7 j5 s% o1 e - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
: e6 x$ f5 L" ~( A j' v - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
" w- T+ P- Y1 e. ? - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
8 U8 T3 q9 M% u: @ - GPIO_Init(GPIOB, &GPIO_InitStructure);
2 l. i, F x9 C1 e - }
复制代码 3.2.4、主程序
% q0 h& X9 ?; a& a; d2 N" j- int main(void): m" y: p/ g9 x
- {
' H. F2 f- f' o - uint32_t i;
( R2 j# x: q8 Q5 z" t" ^ - HSE_SetSysClock();
" ~4 o# i# m/ v7 t$ a. P - MCO_GPIO_Config();
! x: n/ Z; c0 q. L - RCC_MCOConfig(RCC_MCO_SYSCLK); % u. s7 }! y. A1 \ n5 V1 y
- LED_GPIO_Config(); $ g+ d' `) V% l- D5 H) ?4 D
- while (1)
$ L, M* q. a. T+ V& d- q - {" e; ]& ]2 @6 h0 K: M
- 9 F- o6 y& U% a6 G- D# @& a
- for(i=0;i<0xffff;i++);
% X1 B7 v# f( a5 x/ C& ~! t - GPIO_SetBits(GPIOB, GPIO_Pin_9);- k8 `6 {4 _9 W$ K$ J1 W
- for(i=0;i<0xffff;i++);6 P& j9 u0 s$ H: t
- GPIO_ResetBits(GPIOB, GPIO_Pin_9);& U3 U7 @, e% \, ^
- }. [1 a% T' ?' g4 S7 F, b% v Q
- }
复制代码 $ Q: R1 {3 j; ^5 e' n
四、程序执行结果
8 z4 K" v) z6 h. {# y& H7 n% E2 M, V( ]( _; c
& R" X; ]! L) `0 @: Q 4.1、PLL时钟设置为72MHz,倍频系数设置为98 S4 |& G/ y! J" ? R9 D! a
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频
& v1 D/ L5 l3 }/ p8 W9 {" F9 a 4.1.1、MCO输出时钟频率72M
9 x) i0 q/ ]& s' Q+ Q/ F4 w: o
7 U' c# v, t9 A' m3 F 4.1.2、LED引脚输出
! V3 A1 m2 U* z8 o1 N! G
! c1 E8 S9 |, H+ N n0 S
$ k" Q1 ]. A7 S; R p 4.2、PLL时钟设置为56MHz,倍频系数设置为7 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //PLL倍频
]* u8 S" m7 c2 i) P5 L* }( J 4.2.1、MCO输出时钟频率56M
% J; o W' V: F5 U$ m8 `7 k
' v3 k/ r( \+ I 4.2.2、LED引脚输出
" _, b) R- \- F& ]9 Q
1 f) }9 `$ E' L$ ~% h+ D' n
LED输出宽度比72M时钟时,宽度变宽2 w9 B4 F4 k8 Z; N6 O: i
4.3、PLL时钟设置为88MHz,倍频系数设置为11 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11); //PLL倍频& n* j4 O9 _1 w# r: m
4.3.1、MCO输出时钟频率88M3 M4 E4 E4 ~2 j
" E1 x/ z# P9 Q' `; w5 { 4.3.2、LED引脚输出3 o3 ? z$ E: g2 r( h. p, \# d5 u0 I
$ U- J+ H) h+ x: }( E1 M$ H; g LED输出宽度比72M时钟时,宽度变窄
g! ]* a/ _8 g5 E, B0 Z% U2 q U+ v4 @/ a' S
五、结论! K4 P& s# P3 J; y* k- g
! T4 u* Q" k! R! D- M
8 L: z1 i5 {4 L z 使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。
, P% v _/ h) F) X8 m2 T' t" `% \+ K; ~. J+ f! W
% K: V. J/ \1 I8 K* s8 ]
9 n; f J( ~9 \' H
2 X5 o, Y: ?6 G }) J0 U6 s* g0 |; Y6 K* h# s- m
7 |" _7 E. H" M
% @% l ~* ^: Z+ n9 a9 ~) `# R
D9 R* I6 \4 [- P |
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));5 g+ `; I8 m3 V9 \( E! \# o
这句话是把第16-21位清零
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。1 W) c. m9 o- g
0:HSI振荡器时钟经2分频后作为PLL输入时钟4 W4 o8 C K) ]5 i$ V
1:HSE时钟作为PLL输入时钟。
以上是手册里说的
这句话是不是把相应的位置1 这样就能配置了