reset clock control 复位和时钟控制器 一、stm32时钟树 ( D1 ^5 y' r5 c& u9 M: f: b' K5 y- S
9 R0 |3 i' }: b3 R, P1 l$ E4 D, v
$ F2 e6 v, W( M- l
stm32时钟树:由时钟源到外设的结构框图。 基本时钟源(图中绿色箭头指出): (1)HSI高速内部时钟,RC振荡器,8MHz。 (2)HSE高速外部时钟,石英/陶瓷谐振器,8MHz。 (3)LSI低速内部时钟,RC振荡器,40kHz。 (4)LSE低速外部时钟,RTC石英晶振,32.768kHz。 注:内部指的是片上外设,外部指的是芯片外部。 (5)除了上述基本时钟源,还有num3中的PLL锁相环倍频时钟源,它是将HSI和HSE倍频后输出。 二、PLLCLK - PLL时钟(num4) 时钟来源:(1)HSI/2 (2)HSE 三、SYSCLK - 系统时钟(num5) 时钟来源:(1)HSI (2)PLLCLK (3)HSE SYSCLK经过分频后,得到AHB总线时钟HCLK; HCLK再分频得到APB1总线时钟PCLK1和APB2总线时钟PCLK2; PCLK2分频后得到ADCCLK最大14MHz。 四、RTCCLK(灰色框中) 时钟来源:(1)HSE/128 (2)LSE (3)LSI 五、系统时钟配置 系统时钟有三个来源,PLLCLK、HSE、HSI。 正常情况下,时钟配置是在system_stm32f10x.c中完成,这里的的时钟配置是直接控制寄存器完成的。 在 stm32f10x_rcc.c中定义了关于时钟配置的库函数,此时未用。 打开system_stm32f10x.c,找到void SystemInit (void),再找到 SetSysClock()并查看定义, 定义中可知是通过在system_stm32f10x.c中宏定义SYSCLK_FREQ_72MHz选择系统时钟配置函数SetSysClockTo72(), 即72MHz的系统时钟就是在此函数中配置的,函数如下:(HSE(不分频)->PLLCLK(9倍频)->72MHz系统时钟) - static void SetSysClockTo72(void)
( ?1 U0 o- s3 f" ]' I) _ - {
( F1 M3 H, [+ k% D' s' ~ - __IO uint32_t StartUpCounter = 0, HSEStatus = 0;7 D5 r b6 b5 T
- & N2 z: p% C9 U! \
- /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
& B% t6 ^8 o& g+ }3 u - /* 使能 HSE */9 D3 w7 S8 `* n+ h0 M$ t
- RCC->CR |= ((uint32_t)RCC_CR_HSEON);
! L) r, `# Z- g1 j. R9 Z
; a+ B0 X6 Y' c& g9 w4 D% P- /* 等待HSE就绪并做超时处理 */* Q: N: O; m, ~% k
- do
2 l: k$ g7 a# w& m# U - {2 s5 g$ s. _( _- ?8 { q
- HSEStatus = RCC->CR & RCC_CR_HSERDY;
5 H4 d! }9 h) G - StartUpCounter++;
- P- ~3 g1 D7 N0 @ - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));9 z3 x& O0 |8 v' P
8 _# o/ J* y8 v* J- if ((RCC->CR & RCC_CR_HSERDY) != RESET)* R6 `9 T# R/ D6 Y
- {
4 ?7 W. T5 [9 b - HSEStatus = (uint32_t)0x01;
$ b4 z' R9 i& R# f- P- E - }
, v# B# q( o- y* { - else# X0 N' F) {+ K; @! i# v' b
- { `: H( k( b; D8 |, M6 x
- HSEStatus = (uint32_t)0x00;3 c) @* e1 j8 ~7 r% R2 ?
- }
8 ^) ]% r- ^+ m - : y2 |$ h: B% ]# G5 v# L
- // 如果HSE启动成功,程序则继续往下执行
# q5 b) z! n9 i7 D& b+ s - if (HSEStatus == (uint32_t)0x01)
# B7 G7 W( v. x8 N' Y - {1 Y0 E: J3 x. D \
- /* 使能预取指 */, _0 K- N0 D1 M$ B" S
- FLASH->ACR |= FLASH_ACR_PRFTBE; _- q8 e' p* ~5 w
- ) q" E y( Z% ?
- /* Flash 2 wait state */ o) l7 H7 F2 I8 `! n( j
- FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
$ `$ t B3 Q' h1 b9 J& z$ q- Q - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;6 ~3 ~0 J& }/ n
) C! {% y4 q4 M7 Y" p
8 E1 V9 `" _" s& I* [- /* HCLK = SYSCLK = 72M */( L. ^' Q9 x2 u& ]. b& @
- RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;1 R( ?/ z7 |1 V- ? S) R& B c4 h
- + ]6 c/ V8 e$ }9 i
- /* PCLK2 = HCLK = 72M */9 {3 o1 \$ ]. K8 d5 O% B4 h
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;: U/ g; B" B( b
# T |% ]& L) U4 L; u* I- /* PCLK1 = HCLK = 36M*/! C M& V6 R+ ?; m4 V! T
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;& x5 I' l0 J5 W
x6 ]4 v% P4 r5 ~3 j0 M \- /* 锁相环配置: PLLCLK = HSE * 9 = 72 MHz */( [7 o% s5 x, g h1 l: {- c0 @4 ^
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |$ n! _! P$ ]6 j, w
- RCC_CFGR_PLLMULL));
7 s& F0 `1 m6 z - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
: C/ j+ f J' _' l O" w: G& y, B - ! G% u; h: m9 P! z- N2 N% G
- /* 使能 PLL */: O; a* [2 O! n. V4 K/ f% `
- RCC->CR |= RCC_CR_PLLON;
3 J- Q, K: N2 l3 J* ]% d- c - ! v. B2 a/ R$ L( m) o: @5 c
- /* 等待PLL稳定 */
' m$ g2 y1 I3 g0 S8 M - while((RCC->CR & RCC_CR_PLLRDY) == 0)/ L' v' I3 W5 I; y8 E" f7 o
- {
( K! C( ]2 ^7 a0 \8 F: X9 j# e - }; A, A8 a+ `; n/ ?' |7 \$ a
- /* 选择PLLCLK作为系统时钟*/$ ?3 _4 }& V8 C7 i1 e# B0 B- D3 L
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); y% B* Y! s; G2 H5 O: f+ ], m" ~
- RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
5 B3 X4 x0 t3 ?8 b( u! |( h9 J" _
1 b0 [% B0 t( M7 F2 E( T- /* 等待PLLCLK切换为系统时钟 */
" k) a+ u/ N" B - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
8 r3 }$ V: m: C/ o0 K - {
- O2 i% U* m- l7 R8 D; E - }
" P% A# }$ [+ N! e6 c) b - }
, a9 C" E& |: w - else# O/ e1 J+ U) V6 W
- { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */5 L( c' w3 R, e( t# {, z
- }- E& o0 K0 t2 w- P+ J- v; {1 i
- }
复制代码
$ G( }8 P, |6 ]3 o 这里再以库函数形式中重新配置系统时钟和MCO: user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的) bsp_rccclkconfig.h - #ifndef __BSP_RCCCLKCONFIG_H4 F% f/ [& K" i& U B8 M# M4 @* U4 q$ N
- #define __BSP_RCCCLKCONFIG_H
- x6 B5 n! V3 u/ \9 [
3 |! s l2 a% v( _$ L- #include "stm32f10x.h"
6 x0 V! M& g$ {% P4 Z8 U [9 c( { m - : {0 K% a5 r! n/ B# e, w3 J
- void HSE_SetSysClk( uint32_t RCC_PLLMul_x );/ ?; E2 T: [) f4 A+ u/ o; r
- void MCO_GPIO_Config();$ G! F& j* M; u+ ?
- void HSI_SetSysClk( uint32_t RCC_PLLMul_x );& ^- K" L. j; V1 @7 Y& e- g5 \$ N
- #endif /*__BSP_RCCCLKCONFIG_H */
复制代码bsp_rccclkconfig.c - #include "bsp_rccclkconfig.h"
; | d0 k( Y! l% A$ @ - # M% X. H* M% g
- void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
2 U6 q' c2 E" B - {5 f9 O; l& H5 H0 `! C2 F# \1 c
- ErrorStatus HSEStatus;
& }+ G" n- M* c b
. W3 A9 p( p- E3 P0 V! I$ _- //把RCC寄存器复位成复位值
# `4 q# C e, f; v' @- r: u - RCC_DeInit();) W( ^+ W. Y8 h
" _% Q% @3 o& a r5 h, w2 q- // 使能 HSE* Z/ A, G! q+ z! v
- RCC_HSEConfig(RCC_HSE_ON);) Z- q- I3 ~, R# L. z
}4 x0 T0 {# G7 t: X) Y* y. E+ b- HSEStatus = RCC_WaitForHSEStartUp();
2 C" G! H/ S/ j% o - ) ]+ n! ?0 m' M
- if( HSEStatus == SUCCESS ). l2 ^9 o+ Z) `) m0 h
- {5 {* A9 J5 e2 c8 [/ h# ~
- // 使能预取址$ c8 y" X @& y
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);- l( q- j+ @# T3 T( P
- FLASH_SetLatency(FLASH_Latency_2);1 \& \# {! F, ]3 L
4 y3 `% f1 B( }6 M; {8 V/ p- b- RCC_HCLKConfig(RCC_SYSCLK_Div1);4 \3 t: J6 K7 @
- RCC_PCLK1Config(RCC_HCLK_Div2);3 [" j: a2 y2 _+ P; \
- RCC_PCLK2Config(RCC_HCLK_Div1);/ w7 w. [/ l& }! O
- 2 s6 A) ?3 z$ J6 A f
- // 配置 PLLCLK = HSE * RCC_PLLMul_x
2 B. \. I5 j/ w8 u( U) W - RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
2 M7 f3 p+ w, q, s' E$ k! p7 f. m$ P - / l1 }) s" I2 d" J. T% l8 |
- // 使能PLL8 e8 w/ O6 a/ T; p* O
- RCC_PLLCmd(ENABLE); d+ J4 e4 {0 | t3 y4 j. Z( d- t
) q" _! M i$ ^4 I5 K- // 等待PLL稳定
K8 i. U6 r9 Z0 ~/ o) x1 K - while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );6 U" b$ s' G' G- a& D9 \
5 Q0 P1 ^3 Y8 z3 U- // 选择系统时钟# N6 ^- l7 `) f3 u0 |+ w
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
6 [# G4 Y9 O+ Y% \7 G9 c
6 v/ I7 n5 U8 u [/ M/ K1 a- v m0 A- while( RCC_GetSYSCLKSource() != 0x08 );$ J& P( n, W% w" E5 b& V: R
- }
- f) t& }1 E. G! H - else$ ?# Q8 e! Q* u5 A; A' T
- {
1 y6 m- B* Y% D - /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */
. i. I0 |: c% F: V8 U% Z; X" u( L, ~ - }
+ y. `+ g) Z3 a0 x - }
. D, Q3 D* W) {: L4 Y! \- i - Q: ^5 F# y( u- K1 W
- void HSI_SetSysClk( uint32_t RCC_PLLMul_x )( H3 {6 K0 K U5 ?; a( t# ?
- {4 B. F" a4 k+ L% A* ?% O
- __IO uint32_t HSIStatus = 0;
# @# a. U! o9 w! |* R; p& e& { - 1 v% _" W1 f" K/ |
- // 把RCC寄存器复位成复位值5 B) G/ P z+ N Y" J0 }% _ S
- RCC_DeInit();
! B& Q. x% h9 Q, a - 9 u* o/ c5 [ q
- // 使能 HSI: j# M5 b- V) ^, ]! U: M# \
- RCC_HSICmd(ENABLE);
3 G- X- {" E8 R8 W8 u( ~/ Y - t: Y& j5 o4 \$ I
- HSIStatus = RCC->CR & RCC_CR_HSIRDY;
$ M" Y2 {5 h) D: N# {; i8 X
1 e8 F2 J4 I+ V! @3 m- if( HSIStatus == RCC_CR_HSIRDY )* W/ P' f; y; T. Y# x+ f$ I6 U* S
- {- m5 f: C% I- q$ \ x% G' e
- // 使能预取址
: P- m' y) c# q! t - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);7 O5 {" P4 u" B& r, h
- FLASH_SetLatency(FLASH_Latency_2);. P: [' L6 }$ x$ U: q) r
3 p0 ^5 t8 ?1 c# B- RCC_HCLKConfig(RCC_SYSCLK_Div1);6 W$ V- S1 {1 V
- RCC_PCLK1Config(RCC_HCLK_Div2);
; K- x" P. Z5 h4 M - RCC_PCLK2Config(RCC_HCLK_Div1);
8 x$ c0 n+ t6 \) f0 }/ k - * N& ~) |5 C! B3 E$ k
- // 配置 PLLCLK = HSI * RCC_PLLMul_x
1 g4 x+ }1 N# r' x - RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
' L6 J( c- W+ @; T2 _
, R/ d, w. r) P9 V8 h- // 使能PLL5 Y/ |- Q- c. t& A; {5 h
- RCC_PLLCmd(ENABLE);) L7 X! G4 p' w6 `' |8 u* K
% z! k1 S9 U [5 ^; s& P9 h C- // 等待PLL稳定- p! L: Z+ @ J" a! h3 q
- while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
7 `" R2 K8 v( A7 V# }; |8 k# t+ | - 1 B3 Z( ?# c$ T* n
- // 选择系统时钟
; {$ Q# m$ L) T; Z, x: Y - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
6 L: _. A3 u# q& r1 R( I0 | - 6 u! A, S2 f% ?0 O1 b5 Y- D' R
- while( RCC_GetSYSCLKSource() != 0x08 );/ z/ \3 b( k6 E/ ^
- }* F2 ~8 I0 ~9 [, g- h( S- A
- else
; X! A& {0 P. a$ E$ m - {/ G1 q8 q: C/ G
- /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */1 y3 S# E( \. [0 Y
- }
0 N0 Z, [, D* p. p6 g - }2 N$ k& e! s5 W* c! k& n7 M+ Y6 Z
/ k: L# Z, `2 _- void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8
3 ?! V I# n: B - {& L/ Q& n9 o) Z# V: \
- GPIO_InitTypeDef GPIO_InitStruct;
& ?5 x" u$ P# q+ i$ L0 C/ j6 V
3 \3 b# k7 x+ C1 [% i- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
5 X/ J r" i# q - & A, b# }# O I1 ~
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
; U* r; g7 F6 b% T5 N - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
3 { ?- g1 A" o/ e6 L( _6 p1 Z - GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
# X" r" u# A! w; S' W7 V' U9 K
4 r0 C1 }; L. w+ }! p# B. o- GPIO_Init(GPIOA, &GPIO_InitStruct);4 h# l T3 p8 H; t- \7 r" |
- }
复制代码 1 |( b" B/ k' u2 f9 F
main.c - 1 #include "stm32f10x.h" //
. T. D, K; U- }" q* M+ Z2 A - 2 #include "bsp_key.h"
* `$ x: c" E& e - 3 #include "bsp_led.h"
7 b+ @) c" U! Y" u - 4 #include "bsp_rccclkconfig.h"
% L M& ^( Z! `& T5 U - 5 void Delay( uint32_t count ) //软件延时函数,但是实际时间间隔取决于系统时钟
# c2 }/ O- E+ O; H - 6 {* }5 t m5 C+ z) n2 l
- 7 for(; count!=0; count--);
$ R6 p2 p0 Q6 o! t) l3 } - 8 }7 o4 W% O9 r5 ?- e$ z4 |
- 9
3 N* t+ Z* @# r6 f h& D4 Y& f - 10 int main(void)4 h7 U, y" a, f& S# q1 z
- 11 {
; P, X; j& Q( c6 B. q - 12 // 来到这里的时候,系统时钟已经被配置成72M1 ~7 T x5 ]6 w" [- V5 q% D8 H
- 13 LED_GPIO_Config();
/ \8 i; k0 `) M; _! F - 14 KEY_GPIO_Config();
" h# ~& }. K( U5 @9 j' S3 }" y - 15 //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M16 //HSE=8MHZ,PLL九倍频=72MHZ" _3 \( T8 n2 l' I: r
- 17 HSE_SetSysClk( RCC_PLLMul_9 );5 H7 l2 A2 |. _; p" k
- 18 //HSI/2=4MHZ,PLL十六倍频=64MHZ0 e0 o$ F' N" h6 H' {3 d
- 19 //HSI_SetSysClk( RCC_PLLMul_16 );! F2 I. o8 X) A2 i Q) v5 q- X; g
- 20
9 V* U9 ?& `0 H - 21 //MCO的GPIO初始化# d% g8 n5 i4 V) _4 |
- 22 MCO_GPIO_Config();
* z _4 I. D6 v: Z8 c' @ - 23 //选择系统时钟作为MCO输出
2 i0 e- G& H: t; h$ Y* o9 D; w - 24 RCC_MCOConfig(RCC_MCO_SYSCLK); //PA8接示波器可见7 \; u" a* x0 a8 \3 @8 }
- 25 //RCC_MCOConfig(RCC_MCO_HSI);
/ d; f& H4 f0 J/ f; Y - 26
9 H: C" w2 f( t( E - 27 while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化
/ O6 y4 [$ R$ O. t: O# x - 28 {
: s- t& D% G' x1 L5 H; z! U- a - 29 //* X' ]8 T7 K" V8 I
- 30 //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON )
1 n0 Q. f1 u4 R! d& Q& O; @ - 31 // LED_G_TOGGLE;4 t9 @1 E$ w" A4 g
- 32 # U, E1 ]0 `! @, A2 t4 H
- 33 LED_G(OFF);
/ [6 x5 w& H% H - 34 Delay(0xFFFFF);' ]/ g( X( B/ X2 O4 h9 o( f) w
- 35 . [" q0 J7 ?' a" q1 o
- 36 LED_G(ON);- C, c! l! B ?0 p
- 37 Delay(0xFFFFF);
) M( Z3 W) j: y" \# F& ? - 38 }
5 l8 p4 J) x4 x2 q# Z0 ^ - 39 }
复制代码
( o* W( {7 S% {+ E |