本帖最后由 TLLED 于 2018-12-8 14:42 编辑 . J% ^4 W4 k3 O3 M! C" C. J
. C+ r! M, k( C! U' T; W6 `% y 通过第16章节 -- RCC-使用HSE/HSI配置时钟 的学习来重新认识系统总线和外设时钟的配置。 ]+ L$ H- S0 f0 X
0 U) n% l) m/ Q& |: z7 z% ] 一、手册中有关时钟配置的内容
) D- y2 p7 l& B; Q. j+ v! J3 k5 `, ?; B& s+ u
' }* b3 w0 W* L4 @$ t$ n 1.1、系统时钟框图:
! I9 t7 A {- X+ `7 A 里面显示出STM32芯片所有时钟和有关配置的寄存器位
9 c' ^9 z% ~* H- c% h5 i" l
6 P2 @, j- l- a+ G, V& K( v) d& [
2 k6 E: V- i7 p 二、系统启动有关时钟配置代码, y" V' D+ z; ?. ^0 G
5 O% e) g3 }1 g: x 2.1、系统启动分析# z8 ]2 n9 L, p S* Y( `3 x
上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
5 F% [: L- m# w
. y) K s O/ W- k6 J- Q
里面有执行SystemInit系统初始化程序7 {* U; {8 O5 d0 V; e
0 S2 j3 f/ ^3 J- I' K/ \
7 p0 z8 d# S9 u) r
里面调用SetSysClock函数设置系统时钟' s7 I7 r3 @' R
# k) e9 Z: J+ i( R7 l" { SetSysClock函数配置为72MHz后调用SetSysClockTo72函数
4 h6 C6 a) I( v3 v
* b6 \9 \% G' U+ M! ^. K' ]
0 A1 A5 `. p5 ~2 i
B7 h" I- w8 J* u/ ^
0 S/ }1 m$ S4 g' V
上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。
# n* N: p7 K1 t* Z ! T8 ^% P Y8 r& a. u0 r
三、时钟配置实例3 f" A) k7 M1 Y+ _. @9 w
# |( c7 G1 G+ X
: B6 k8 G' L+ Q, N5 w- b- W
3.1、配置HSE时钟 - p# b0 u/ [ g& k" I9 Y- o2 ~
了解系统时钟配置流程后,来实践使用时钟配置。1 Z3 n0 x! S+ I: A# k
在系统时钟框图中,HSE时钟配置0 S0 z a4 a; N: H% M" d. b5 d
8 f w; E3 h: W) H >选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振2 s+ L( O1 |7 |5 S7 o( S" h
>通过PLLXTPRE来选择HSE时钟不分频还是2分频。
0 B/ q% {3 s: y f >通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。
9 @% B: p$ E. h6 C0 O/ o >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz/ j$ \' x: Z* W6 y* R' Z
>通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。
; v% O5 i' b' J0 Y t6 c1 ^) H% z! _: |- ^" |0 X, C1 P
- N" P/ [$ @6 e) e) w# g" ~+ Z8 T 3.2、程序源码. r7 I; |. z1 b4 E& p& i8 d0 l o
3.2.1、HSE时钟初始化8 k" c) T4 x. d5 T" b% f
PLL时钟倍频到72MHz6 U: j" I7 T+ i- Y& s0 }, \ u* C
- static void HSE_SetSysClock(void): C1 I2 l4 y3 E
- {
4 N/ a |# }" H9 L- a- P1 v - __IO uint32_t StartUpCounter = 0, HSEStatus = 0;4 }1 {" j! H, X B; w, x/ f
-
) c6 F/ Y. k2 q: r- f8 W7 E" w - RCC_DeInit(); //RCC恢复默认状态 & I8 U2 J( M; T1 P- u% R
- RCC_HSEConfig(RCC_HSE_ON); //打开HSE时钟# o6 z! f4 a0 @/ A; C4 o6 x$ X
- : a" z: a" P* r8 h3 e- S8 A/ t
- HSEStatus=RCC_WaitForHSEStartUp(); //等待HSE时钟稳定1 h0 z( q- |& t# y/ E: E! l
9 M6 H7 j9 `! E( ~. [8 l- if (HSEStatus == SUCCESS)
8 _) Z4 ?- s4 A* b# ~ - {
) @7 C: [" J% _3 _& @1 R. X' m - /* Enable Prefetch Buffer */
: N! g0 E6 V6 S' C* _ - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区
+ Q3 \( `1 H8 h4 z. _; p6 @* l% h - FLASH_SetLatency(FLASH_Latency_2); , `5 x# T! ?1 |/ b2 O* P
5 Q$ k, q5 C9 W" T* y8 c- RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB - HCLK=SYSCLK% F4 @7 Y3 y( a" b, Y
- RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 -- PCLK1=HCLK/2
5 J. y4 W# `( H8 q - RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 -- PCLK2=HCLK
9 z2 N3 J, m2 P a& c - # \2 V$ G9 o6 k( M3 V
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频
5 o+ W( Z& K' e - RCC_PLLCmd(ENABLE); //使能PLL
, |$ s* \) i& T - - Q# X& t# P/ A- I& m4 y0 Z1 Y
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //等待PLL稳定7 n. j+ C% J% ?, _/ e
- {' O+ z% v9 E, _. {( \0 h0 T
- }3 }7 a- K% `( w" x) j
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //PLL稳定后,时钟切换到SYSCLK
0 R# @. r" @1 {/ Z5 M2 x -
* M8 n6 O$ }" I( F# U: R n I -
, ~* H6 t0 E0 @; f - while(RCC_GetSYSCLKSource()!=0x08) //读取时钟切换状态位,确保PLLCLK被选为系统时钟
5 M: f' m$ _( Y) t* A - {- G4 u8 e [( n8 Y, T7 ^( c
- }6 p- o( |- ?5 e7 i8 w
- }8 o, j" n; O8 O$ F% c9 ?
- else& p5 v |& E1 b. P7 ?/ W* U( q, l
- {; f4 v! c3 P7 r: [8 M
- }9 e& d% d8 @; i: ?
- }
复制代码 3.2.2、MCO引脚初始化! S& R# |3 g% }4 ~7 j
- //MCO引脚配置
+ v. E& l a1 }6 e5 |4 q - void MCO_GPIO_Config(void)
6 E8 L( `& D3 f: g2 s% }( j) _ - {
% ~ Y3 t& _$ m9 P8 O! }* o - GPIO_InitTypeDef GPIO_InitStructure;
' R' _9 u7 K8 w4 g5 ^9 d -
- @# V+ h: }5 ]" Z/ Q - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
: Y( P3 G' \; o9 m6 h. F+ o -
$ J$ E5 b. Y1 Q2 I' l - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
7 {5 @$ K [: R% U - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 7 i1 R. q, K' O3 _
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
; f" i% A. M0 U) {: [ - GPIO_Init(GPIOA, &GPIO_InitStructure); {) t" G7 _# Y/ l! v6 j
- }
复制代码 3.2.3、LED引脚初始化
v8 ^6 T6 x/ `9 m
+ T' ^; C' c/ ?! }- L- G! M- w- void LED_GPIO_Config(void)
$ X0 U5 [6 r* u9 l& Z - {- J' Y8 I2 @8 I4 w
- GPIO_InitTypeDef GPIO_InitStructure;
: V* A9 w# h5 ^7 u - ( D M9 ?* r* S* R# C6 Y+ o
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟
! v6 ` m, v7 o' e1 s -
9 {8 A, F5 p8 c9 c3 T$ r - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
8 M/ o3 K6 T, ~& D - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
0 K' F) Z& O" |7 S# a8 u' W) u; M - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
' y5 I7 A& g# c6 h' q# }! Y - GPIO_Init(GPIOB, &GPIO_InitStructure);
6 h* x3 i3 x. H5 x! N7 _$ [ - }
复制代码 3.2.4、主程序& _8 x0 q# J" ]$ W7 d0 L( ^ y
- int main(void)
/ J9 Z& P" X* E - {, H: W x- h& S$ `* H- B2 h2 ~: I; w
- uint32_t i;: o1 V( Y* O w8 p* l
- HSE_SetSysClock();
1 Z1 k g0 E& N) F2 _ - MCO_GPIO_Config();" W! w7 j! M6 N- a8 b- `: o% p( d0 ^
- RCC_MCOConfig(RCC_MCO_SYSCLK); $ m K6 t, n5 h; d( B, ?8 E5 t
- LED_GPIO_Config(); $ ?$ a- b/ }+ X' @! w x
- while (1). x3 N7 x# c! t
- {, D& h; {6 l: o5 x0 t: n. V
-
8 J- j1 {0 U Q$ R1 { - for(i=0;i<0xffff;i++);
( E a) M2 A5 I - GPIO_SetBits(GPIOB, GPIO_Pin_9);9 ]& W& Z& v6 R" F, ^" b v
- for(i=0;i<0xffff;i++);
1 L" Y# w0 k: e6 q; ?7 [ - GPIO_ResetBits(GPIOB, GPIO_Pin_9);, c m% j- ?( w+ S1 c& \
- }
. U% P5 ?2 {! X5 K0 g1 w - }
复制代码
8 x" I. q: V$ [# E# R, D- ~5 G 四、程序执行结果) g# N9 p; B, H1 n% L: b! \
* G. y: ]4 r/ Q: C, u6 W
$ B9 P5 {. K% ~0 G6 A 4.1、PLL时钟设置为72MHz,倍频系数设置为9' c0 w1 [# Z0 f5 E8 @
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频
* M$ z" B7 ^( [. [1 z 4.1.1、MCO输出时钟频率72M
" S) a2 b( v6 |
. K2 ^* m" c" V3 ?: N 4.1.2、LED引脚输出
( J% s, U' s4 B* N7 n, C, M
1 i- @) r1 k2 n2 j
5 R9 e* X! S6 ^ 4.2、PLL时钟设置为56MHz,倍频系数设置为7 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //PLL倍频4 k) Z. o6 H, b2 |% B
4.2.1、MCO输出时钟频率56M9 w- X5 H% _' R4 |. d# T: @
6 h" C* S% p1 B9 m! O
4.2.2、LED引脚输出
`7 Z9 _' [- t
7 R8 Y) j7 c) n. h LED输出宽度比72M时钟时,宽度变宽2 }7 t3 `0 ]3 d* k8 g! }; h
4.3、PLL时钟设置为88MHz,倍频系数设置为11 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11); //PLL倍频# O- h9 w: q1 M" t# n2 `8 K
4.3.1、MCO输出时钟频率88M
( {, _* j$ R( B b" z1 R
0 j G+ o8 E$ j- o2 B
4.3.2、LED引脚输出
. N' Z& R2 X) B
* P, d6 w5 G2 T! g3 @ d LED输出宽度比72M时钟时,宽度变窄1 y: ~/ f* F7 e# y7 X
1 O& r* F0 d5 S0 T1 Y, H- l* _
五、结论; K, g4 f$ O+ D* e/ X7 C
' K7 [7 O. {! w1 Y; E5 u
% w$ A! U0 f [
使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。
3 y& y7 E8 O- s8 p: W0 ^
& O9 k5 j, v0 j$ `* o- D8 r
2 F) S( X8 k$ {' _8 m8 n6 I+ |1 l% W+ \9 e/ q' X7 }
0 J' M% L* f! n7 w
7 t5 T6 a3 F% A ?# t- t) J9 x
/ S4 _! w1 [, H: l& {1 @) C4 j8 I) P5 h0 q* E X' w u7 H
0 O" d# M# B2 a# W$ y+ h5 ]
|
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
这句话是把第16-21位清零
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。
0:HSI振荡器时钟经2分频后作为PLL输入时钟+ \+ R( [( Q/ U/ A8 S; R7 {8 D; q
1:HSE时钟作为PLL输入时钟。
以上是手册里说的
这句话是不是把相应的位置1 这样就能配置了