本帖最后由 TLLED 于 2018-12-8 14:42 编辑 8 L! L" u$ w0 K$ V9 v( ?' q
8 A/ b9 P* q9 W! c% P: h
通过第16章节 -- RCC-使用HSE/HSI配置时钟 的学习来重新认识系统总线和外设时钟的配置。
- H; m4 P& u* s) u z
1 I$ g6 _4 a, |* V# m' Y 一、手册中有关时钟配置的内容1 ^+ G" V, o+ Z3 d
" i0 f n- u: [: \
2 T- L$ M# Y. I ]2 G: q 1.1、系统时钟框图: ! d0 m7 A% B0 E" U' K3 B; D" ^
里面显示出STM32芯片所有时钟和有关配置的寄存器位
: @6 A- H, K8 F4 ?# f- _; |- p! W. E! z8 I/ H
) C2 B+ ~, R# y 二、系统启动有关时钟配置代码3 f5 a% w% ?; U T. @
/ M6 z: U: [$ {; A 2.1、系统启动分析
, O$ P, B/ @" G# X- L 上篇介绍启动代码分析,会执行Reset Handler服务处理程序。 S0 ~0 C% a$ m, F
8 _" C* S+ Z# t/ Y4 ^, h6 Z$ u
里面有执行SystemInit系统初始化程序0 I% D! i9 w) P6 x, u, P
& |/ \5 x0 v, k% P; U1 e
. ]7 j# [" T& U# j( o& _
里面调用SetSysClock函数设置系统时钟
4 O! E, B7 K, e. o
" d/ h/ k1 ?$ N# v1 M ` SetSysClock函数配置为72MHz后调用SetSysClockTo72函数
4 s, j% \9 I/ H# H. s9 S
! D; _* @* c& _* j
* a0 M% q/ g. {: x
* S0 n2 j: o H8 v3 X- D
$ s# {0 d5 x2 `* W( Q8 C1 h
上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。( G9 L: ^) T% _: _& J
4 i+ X" J; a* M$ ~* x' s 三、时钟配置实例
# |! S* c" e$ Q/ L$ H7 L, \: ]$ s$ g3 @4 e+ B# n
6 s$ l! {( c/ g0 c
3.1、配置HSE时钟 9 d; K; U9 b# j! E9 F
了解系统时钟配置流程后,来实践使用时钟配置。: f( b7 b" Z+ z# h9 R
在系统时钟框图中,HSE时钟配置
0 s# }; u' f' |; z5 w) B& |) g
1 ]' \+ h1 R5 P( B/ ?
>选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振
0 b4 A: \" j3 f/ J9 ~ >通过PLLXTPRE来选择HSE时钟不分频还是2分频。
$ t# r9 g/ t& Q* W1 X- Y6 g" B >通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。$ v3 |! o- J$ l3 @
>通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz: V2 j9 ]) M& S0 ]. @4 x& u7 I
>通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。
V8 ]# y1 a" F. {" x
6 i7 T3 O* [" @, I( B6 `! a- K( |
3.2、程序源码' i, a6 w9 g4 c4 }- K a, ^5 {* {
3.2.1、HSE时钟初始化
2 ^- i0 g' l# E/ r& i$ j PLL时钟倍频到72MHz
) U. q# o5 h$ R, y! K! N8 F7 Z - static void HSE_SetSysClock(void)
8 b1 T8 ~! F `3 Z$ Y* L2 z0 S - {' B$ u; s ~0 S4 Y
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;6 w9 _. _9 Z" f( ]7 u* O3 ~8 _
- ; z9 n" s! Z* |7 f0 |
- RCC_DeInit(); //RCC恢复默认状态 , w5 l8 u& P0 m _
- RCC_HSEConfig(RCC_HSE_ON); //打开HSE时钟 R* G, a! x5 s
- 4 U7 j0 x" t- I4 e; g8 |8 H# @
- HSEStatus=RCC_WaitForHSEStartUp(); //等待HSE时钟稳定6 i$ A; k4 {% j& g' o I. W' }
- j# f. E: \& F# ]8 \" H: l
- if (HSEStatus == SUCCESS)8 i2 C6 x2 c3 v5 X
- {! I" s# l- F( j$ C# h
- /* Enable Prefetch Buffer */4 |9 F% Q2 h1 v* E
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区, M( a% l3 ^( \# @5 P9 P
- FLASH_SetLatency(FLASH_Latency_2);
( ]* b1 i( V. N
8 N- n$ e/ ~& z# M) z T; w! J$ g- RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB - HCLK=SYSCLK) u+ V. A' O& S4 d) V
- RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 -- PCLK1=HCLK/2- ~3 O# f$ U1 s* j. R% \
- RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 -- PCLK2=HCLK1 s) g' L+ _5 \+ h
- 3 Y7 O, t6 \0 @1 a. K
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频0 y/ v3 [( N1 a* r
- RCC_PLLCmd(ENABLE); //使能PLL
* V* Z$ J( t4 F6 l3 G- K - . K2 }* O; ~& R9 J) b: Z. V: R
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //等待PLL稳定
4 P/ ^6 A/ I; T. T3 o8 C) W - {
" M+ |% S2 ` V# k. U - }
' J0 E2 h: V2 |/ N- K/ U - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //PLL稳定后,时钟切换到SYSCLK G% A2 x- S& ^
-
6 C8 L/ q! f5 x9 k5 n: G3 @ -
7 {- }- v Y+ Q8 C5 D' t: C - while(RCC_GetSYSCLKSource()!=0x08) //读取时钟切换状态位,确保PLLCLK被选为系统时钟
+ R, w- k- y4 Q* x6 d3 j - {
, S& G" Q$ f# B+ C& x - }
q; ]) e& z7 a; s8 O. C - }. U$ q+ q# ~. U( c- K
- else
2 ` [8 v4 c+ `' g) O! _ - {
& F5 z; u8 O1 i- Q% |2 @- q - }
* `& z8 h" I# C7 G3 j - }
复制代码 3.2.2、MCO引脚初始化1 X. R0 q) H) d$ x
- //MCO引脚配置
( S+ f9 q* \$ _' E2 I8 B v y - void MCO_GPIO_Config(void)
% R3 h$ i) C7 m; M8 c - {+ D0 L; |2 k4 U2 ]% m. E% r
- GPIO_InitTypeDef GPIO_InitStructure;
3 t3 z) F8 @( B; z5 i' r0 C - ! I8 r- P* g1 c0 E5 P8 C; o" o
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟/ ^1 C: I6 j7 O3 U5 x: t9 s( F
-
3 [5 k+ ]! M3 i' U, w - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
8 K: ~6 X4 ]7 ` - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; " e6 o1 ^8 f" G# a1 ^) y
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
2 u& v; Z1 |7 d% y - GPIO_Init(GPIOA, &GPIO_InitStructure);
) m& I$ a3 Z( U4 A - }
复制代码 3.2.3、LED引脚初始化
8 J! b) [" z8 i7 j4 X0 m- ' a- _" N: y N. X: q- h6 f
- void LED_GPIO_Config(void)
/ Y' e& Y. \" Q6 ~# G4 g; {" E- H( j( W - {. j) O p2 B( m) J2 }
- GPIO_InitTypeDef GPIO_InitStructure; m8 j& j3 K0 f: q; z C: y
- 9 P; \& ?, U$ b7 Y3 c, o4 b2 [
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟: \" E9 m7 j. d6 o
- $ E' N( q. }) r
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
) i( t7 B9 L) K7 v {& x6 a - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 1 `; _# M5 I( o, T- k
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz E6 _9 V2 o0 q4 r6 G, E; ~( C f) ]7 ?
- GPIO_Init(GPIOB, &GPIO_InitStructure);
/ B6 W: L# {* @: v6 y# E3 { - }
复制代码 3.2.4、主程序
9 f( U9 `' m8 ~6 a- int main(void)3 b1 t& u. v% ^; M
- {
7 {' F7 ]' d) p" }8 N - uint32_t i;/ z* R& F+ y# Y8 o0 H5 c* Q& j
- HSE_SetSysClock();
4 ^/ g1 K$ ^0 W3 L# E - MCO_GPIO_Config();! x( a: a2 j* f" a8 C
- RCC_MCOConfig(RCC_MCO_SYSCLK);
& x- Z& |: t* G- z6 h/ V - LED_GPIO_Config();
3 c. C: n: G# i8 P3 [, d' ] - while (1)3 w+ H0 d& v2 | H6 v
- {: m( P: |* J/ y
-
# |3 V4 H! K1 _ X/ n. j, D9 f - for(i=0;i<0xffff;i++);+ E' W( s) W1 g5 k9 t$ f" q
- GPIO_SetBits(GPIOB, GPIO_Pin_9);- G$ Q1 A1 w& u) _- o
- for(i=0;i<0xffff;i++);
7 m W7 w+ Y! N - GPIO_ResetBits(GPIOB, GPIO_Pin_9);% T6 M) Q& u- I& L. G2 u! M }
- }
1 ?/ n9 k# j- K& f5 Q8 f - }
复制代码 1 r6 D2 }" E( k) D) O% E7 A
四、程序执行结果
. A) E3 E( m& n/ H, u: t' F& y- q" B/ {- I) r) j
) E7 u* @# w, p: ]
4.1、PLL时钟设置为72MHz,倍频系数设置为9, Q- d/ [" H9 y
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL倍频
8 ? H/ @; h1 X4 k% h( y/ I 4.1.1、MCO输出时钟频率72M
( L$ g0 y1 }4 f! @0 f
/ y* x* B8 `- q. n S 4.1.2、LED引脚输出
; K$ ~3 y8 J( X1 {$ |9 `
" N S; d7 m9 Y8 \2 o& V1 I4 N. T" u, t! B* D) R M
4.2、PLL时钟设置为56MHz,倍频系数设置为7 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //PLL倍频
! t6 d9 g' F) U' i$ |( Q 4.2.1、MCO输出时钟频率56M
) X4 S" Y# A# v( |9 D* A0 o
9 V) L, g, B! k5 x2 T 4.2.2、LED引脚输出
5 S' S$ O" _- X4 ~
; i- [4 g7 ]! S9 m4 W" R
LED输出宽度比72M时钟时,宽度变宽
8 e* x( k0 h1 T' [% b, r3 x 4.3、PLL时钟设置为88MHz,倍频系数设置为11 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11); //PLL倍频9 g$ }; A b4 d- t
4.3.1、MCO输出时钟频率88M
( f9 B/ H6 X2 A) z _
$ C' N' y5 V8 Y- p; Q- e+ s 4.3.2、LED引脚输出/ S* t8 f- S) ?0 C, _
: j u; P/ p' x! N8 f. N& U LED输出宽度比72M时钟时,宽度变窄/ i I0 d) `0 A% e+ y- g4 Q* l. s
; _3 o5 H/ Y- Y; O
五、结论. e4 N5 H' E! { }8 s
( O. {; L' V( V1 [( y. z1 n$ b3 d
: U* Z+ H M6 c! A% l 使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。( B% M; ]* e+ [# U \! o
# V5 x* y. g0 E* c" d* M7 ?9 B
3 Z" i' f5 H7 c7 r$ c- }1 r
; Q& }+ N4 N: q. L- S* c
Q1 H+ E5 p2 a0 R4 u9 P# O" x' f& I/ ~4 L+ i1 ~8 y
4 L1 z( J6 `, A9 e: z# {
4 Q; a1 S0 C: L$ f) m
' u& j. c3 q4 S' D3 I+ I6 g: Y |
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));& o( H* m% C8 V0 h+ J5 |, f9 q
这句话是把第16-21位清零
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。5 v" N3 u# K( {2 e
0:HSI振荡器时钟经2分频后作为PLL输入时钟; V4 q! E8 l* M" U
1:HSE时钟作为PLL输入时钟。
以上是手册里说的
这句话是不是把相应的位置1 这样就能配置了