|
reset clock control 复位和时钟控制器 一、stm32时钟树
- a9 I& w# }% w0 _ C
0 l% n2 B% b) Y7 A& k
& G, x- ~# D/ G8 j( }1 x3 V 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)
$ w0 c' d, e2 K* h- u! d. { - {
) {& ^$ \" x2 H1 j9 b4 L. S - __IO uint32_t StartUpCounter = 0, HSEStatus = 0;- D4 i: ]& J! v# s2 ^
8 G: I) i- ?- D. ^1 t! O9 H3 t% Z- /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ K. k) r6 B& d% X( ]4 H5 ~
- /* 使能 HSE */
8 G. N; @- {% _, ]* t; F$ ` - RCC->CR |= ((uint32_t)RCC_CR_HSEON);
5 \9 u7 B! c u w1 \; x$ [' k
: J( h, J8 }( F- X+ G- /* 等待HSE就绪并做超时处理 */
+ J/ C* ]; e' L- M2 J# |' v9 ] - do
/ a- t, }+ \5 ]% H/ c - {
) s8 t/ g/ f; A1 U$ o i5 ]) f - HSEStatus = RCC->CR & RCC_CR_HSERDY;
' Y% `; }7 k+ V% `5 K9 Y% }8 K - StartUpCounter++;8 E' k/ d2 A5 E `0 h. _, u1 o
- } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));6 m ]4 h. R! f) X3 s! n( V [
- . L" M5 k$ n s: x- \, }
- if ((RCC->CR & RCC_CR_HSERDY) != RESET)
% T: x" e* |! `% q6 r& N! D+ D - {
9 Q9 d9 { W& U- X% l# {$ _ - HSEStatus = (uint32_t)0x01;8 V4 o+ ]8 _3 w' T
- }& a/ K& F9 r/ E3 U9 F
- else" g% F9 Q) b# ~. ]" ~5 a( w9 ], Y! G
- {
1 T3 C5 P( b, o1 c - HSEStatus = (uint32_t)0x00;& q7 H: W) G$ B8 m* D
- }
; `) P, X, O/ }2 U6 Q
4 I n2 _$ B( [% l- K1 d' a. J. b w- // 如果HSE启动成功,程序则继续往下执行5 v$ A# I; R1 w) o8 S% s; m! h
- if (HSEStatus == (uint32_t)0x01)5 V J @& \) {8 ^6 d9 p* C) \" U; O
- {# K, V4 H# R# R. L: J2 R
- /* 使能预取指 */
' s R- u* q8 ^) [8 Q8 s - FLASH->ACR |= FLASH_ACR_PRFTBE;7 B1 ?% j; [: W9 [
; @; X& x+ M3 ?, {7 D: M8 m- /* Flash 2 wait state */
0 X, w, ^2 g$ j1 D) x" F - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
6 w" s$ D: C$ Y$ ] - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;- p" W& x; \! q& Z, v- k [
2 {& n% [2 f8 ?, h+ ~ q/ q1 Z
5 X0 `+ x/ d9 z- /* HCLK = SYSCLK = 72M */
- Y Z+ B2 j% W- I8 G& y - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
7 J9 P' W+ R0 H. H
. ]3 M: @9 d: ]+ f- /* PCLK2 = HCLK = 72M */
; K G- Z, f$ `: t - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
7 m/ Y- m4 r8 g) T% i f8 f" [ - 4 Q+ o$ y3 T+ M/ p* ^1 B
- /* PCLK1 = HCLK = 36M*/1 ~2 k+ E: g. t" t
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;5 a5 B$ l g- E. L6 H
- ' {; _' C- w+ a( g# t
- /* 锁相环配置: PLLCLK = HSE * 9 = 72 MHz */9 h+ a9 {2 [: k4 U; L( A
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |- N. L9 C2 |$ T4 e
- RCC_CFGR_PLLMULL));& J4 i0 Z5 Y7 e5 Z+ x6 V
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);' x& q; i& G' M3 C, J
- : O) M2 q9 D/ c/ P& [) O2 G+ r
- /* 使能 PLL */
V+ W! c# T. W, m! R* S8 i9 }/ T - RCC->CR |= RCC_CR_PLLON;
1 J* ^# T# I0 J
9 D& B' a' I9 p1 O4 S- /* 等待PLL稳定 */
* S, e, o/ S* f9 r+ x3 W# M - while((RCC->CR & RCC_CR_PLLRDY) == 0)1 N# N4 \; Z! V# H
- {8 L- C$ L2 p: a1 x
- }
" Y! K* X6 r) g8 N1 o+ A" x% ^ - /* 选择PLLCLK作为系统时钟*/; f9 E) ^$ c2 g
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
3 X8 c; k5 a. a3 _, t - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;4 e# {- I$ `/ n
- / I* I# t- z4 c& H3 E
- /* 等待PLLCLK切换为系统时钟 */' Q- m/ @; y. E' X
- while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
3 F# e6 i3 P2 B4 J" ^0 S - {2 }3 y$ f' e7 t4 \) j1 C
- }
, _% _6 W' U. u J5 v - }7 B& Q% g) J4 J$ M' e4 N
- else
9 i7 G$ a) `) q. O* b4 H9 j. u4 d7 ? - { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
! Y* _" X8 d7 ~1 V' r G9 [ - }
; ^- M- S( G, q - }
复制代码
& A6 j; A$ K+ s6 l Q1 L6 p# J* j 这里再以库函数形式中重新配置系统时钟和MCO: user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的) bsp_rccclkconfig.h - #ifndef __BSP_RCCCLKCONFIG_H
* D' W: M: q/ z; e/ | - #define __BSP_RCCCLKCONFIG_H1 o9 O, C% c8 |. P9 ^
" c7 h* r. k& x9 n9 V- #include "stm32f10x.h"
. ]5 J* j. B, K6 }2 e C
; L9 ^& m+ p) |# n# B2 ?0 [, E6 R; Q# ]- void HSE_SetSysClk( uint32_t RCC_PLLMul_x );
" a; [+ g0 H- J - void MCO_GPIO_Config();
8 k1 w" z. q1 E' x n' r/ c6 [ - void HSI_SetSysClk( uint32_t RCC_PLLMul_x );! i! n e- H, G# c. b9 n; Y) D
- #endif /*__BSP_RCCCLKCONFIG_H */
复制代码bsp_rccclkconfig.c - #include "bsp_rccclkconfig.h"' t$ c$ P: k. ?) y5 t1 @. Z
! n9 \" X( b3 w- Z7 c- void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
2 Q4 H) w0 |8 M0 ^) e8 G7 _ - {
$ Z, {) L8 G# h - ErrorStatus HSEStatus;, j7 Y$ H! v, L! Y' J% h( Z& A* K
7 p* m0 q c" _5 L/ u- //把RCC寄存器复位成复位值
3 B1 O* X% I) a- J - RCC_DeInit();- W& b0 |. D; L$ S% y* |+ }
* d* e: r2 ^# F, d+ \- // 使能 HSE" o, I6 n9 C- L8 u: u, w1 D
- RCC_HSEConfig(RCC_HSE_ON);
& h7 L8 l+ c6 ^: y' g
; k0 i4 E: [; q* R) R0 w" ?, \) f- HSEStatus = RCC_WaitForHSEStartUp();& Y! t! M2 t m1 b
- ! }4 M4 W9 s; f) O/ X5 O; o
- if( HSEStatus == SUCCESS )
9 T9 z& C; C3 H+ m. E2 H - {
2 {4 x7 |# \% Y% C I - // 使能预取址
. ]/ M" Y5 K% M" F$ z! l - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
; _! o9 t0 g8 G4 T5 t) d d - FLASH_SetLatency(FLASH_Latency_2);
) k0 Y A% o7 E( z
) n! |: Y: U4 ]* x7 g# J- RCC_HCLKConfig(RCC_SYSCLK_Div1);
2 M& v& k# K$ [$ o5 H: H$ M - RCC_PCLK1Config(RCC_HCLK_Div2);& J) o) p4 I9 n( L6 c1 C
- RCC_PCLK2Config(RCC_HCLK_Div1);
- r6 v3 {' P" w+ q/ s) E - ; z, D! S% j0 ~7 W1 f( z9 m
- // 配置 PLLCLK = HSE * RCC_PLLMul_x4 L( H8 z0 F! ^) |9 n. A* j
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);3 s1 z: H1 ^6 i7 z
, Y. f( c! p& A. R2 ]' r) m# P' j- // 使能PLL
- ]8 A6 L/ A! d6 \) B) U* p - RCC_PLLCmd(ENABLE);
/ [/ g3 \$ h8 J0 W5 l3 q
/ R; V, h$ O* t. e* A- // 等待PLL稳定
# b! E# L1 C6 c! [ c c - while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );3 K0 O* I; f# t! R S9 u
# J: B: B+ r8 j. _; l- // 选择系统时钟* A. Q5 n- Z4 o! U" n
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);& ~! O0 J i: u. j w
" {# m2 Z, j" U, ]. w- while( RCC_GetSYSCLKSource() != 0x08 );4 x# \" a& y1 S h! S
- }$ M( C- Z9 G6 b3 x
- else* c, g& D$ X+ }
- {
Q( k$ D# R( o9 n8 _7 P - /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */8 B/ I" O9 I0 {$ u
- }. A# M$ q9 P( `, e! ~1 M. ^
- }$ |) j( T! W( F- X
- , }* d( v+ S1 y. K& b/ Y V
- void HSI_SetSysClk( uint32_t RCC_PLLMul_x )
& l# y) ~ L8 m8 N6 z9 j/ R2 N - {
/ f9 p4 E5 E* W7 u5 }% |3 U. i0 Q3 x - __IO uint32_t HSIStatus = 0;+ R0 Y3 R' N# b7 t/ b- |
- 3 g9 W! a/ N/ u' t4 R
- // 把RCC寄存器复位成复位值3 u; j6 ^; P- R! p; ]/ d
- RCC_DeInit();9 ]9 R% p x4 g6 |
- / t d9 `& q7 {( ]8 H' `
- // 使能 HSI
- G) @$ X) Z7 n0 R. l5 Q - RCC_HSICmd(ENABLE);" \8 P* G S; l# M5 o$ }& ^& x) X; A
, U* ^# i. h- C+ {- u) W- HSIStatus = RCC->CR & RCC_CR_HSIRDY;0 p J% ?7 }5 I+ p) F
- " J0 j8 o' ]2 f; \) `+ T$ {
- if( HSIStatus == RCC_CR_HSIRDY )
+ [4 I! D K- n' {" {) ^ - {& c* D5 z, v+ C
- // 使能预取址: O4 ^' h1 W, R. k+ t
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);% K8 d. e0 Z c0 I, U x0 J9 R
- FLASH_SetLatency(FLASH_Latency_2);
6 _ T% i2 Y1 W/ f& }( }; a - ; c* O2 X- w! N9 H7 J
- RCC_HCLKConfig(RCC_SYSCLK_Div1);
$ L- x' v; H, z; |! v3 T0 C' K - RCC_PCLK1Config(RCC_HCLK_Div2);
; D$ V. _: E! W9 N7 [; z - RCC_PCLK2Config(RCC_HCLK_Div1);0 c; {9 c @/ j; F. d* t+ J
- 1 F5 u* x+ h+ S
- // 配置 PLLCLK = HSI * RCC_PLLMul_x
" L. h2 @; g" e, e5 ?, b% Q+ z - RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
( [7 G7 a" s7 @ L4 W$ u/ a2 V
) v( b4 @8 z: K- F* r- // 使能PLL
3 c+ D. A5 h2 O' Y6 m - RCC_PLLCmd(ENABLE);2 X7 ~8 k$ t3 y5 I/ f" c
- $ x! Z0 w# n6 n% A+ n* |
- // 等待PLL稳定
5 x1 v" F9 X( _0 S+ C - while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
' q& H' {4 x) B" T3 _3 J
4 T9 Q% J( s* V: C4 _- // 选择系统时钟
8 D$ ?& @9 x- z: q9 O& x' {# z$ n - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
9 q& o7 o! J: m! B# D4 d
( d1 L1 `" c& a# x- while( RCC_GetSYSCLKSource() != 0x08 );
! A1 ?$ Q6 D# S) e - }6 b& K$ r( i) w2 E' d
- else( q6 d/ x4 [% s* D/ ]3 T7 [
- {
) v! r& [8 {0 Y - /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */2 d9 Z, _: s6 h7 z g. g; P
- }/ J4 L3 n# E' [% B+ M* `& A
- }0 I3 t+ Y" q2 d ^3 d9 [
! {4 K; a3 U: }1 k- void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8! ?2 @% z: ]. K5 j( i; Q9 ]
- {
) x9 z0 ?# V( Y# [' V - GPIO_InitTypeDef GPIO_InitStruct;/ T A/ ]0 {9 ?* `
- e9 H2 i% x. e' z; M% `. `$ @2 D
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);8 k5 `& _7 B; ^
- , r) U; x; ~6 c
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
) ^( r% Y5 S# G( d: _ - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;2 B) o9 n5 s }( ^: O% o
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
! i2 N0 I! ]" F- g
4 {+ H( V2 u% N- GPIO_Init(GPIOA, &GPIO_InitStruct);- B7 R4 V# {/ t5 k, T
- }
复制代码
( X r, X4 J- i. [0 lmain.c - 1 #include "stm32f10x.h" //0 e( y0 G8 X6 _2 ?2 X# b
- 2 #include "bsp_key.h") a2 q f/ r3 S7 B
- 3 #include "bsp_led.h"5 h9 w; {4 {- X1 o# r6 W
- 4 #include "bsp_rccclkconfig.h"$ m9 ^+ e9 b, H) L% s
- 5 void Delay( uint32_t count ) //软件延时函数,但是实际时间间隔取决于系统时钟) M# y. G) _- D6 J9 V& I2 e
- 6 {. d6 ^ d" G% Z/ r: e% s
- 7 for(; count!=0; count--);
6 o" `# k; g4 K5 O+ t, w& V - 8 }
1 x, w B+ ]* g# e8 A1 U' }* x - 9
, h2 n+ F+ l! j3 l8 h) V, | - 10 int main(void)+ c k2 C) i0 \( }0 X: s6 W# L
- 11 {7 ?: M; u L; u0 [' J6 u+ j
- 12 // 来到这里的时候,系统时钟已经被配置成72M
9 V5 u! ]- G1 R - 13 LED_GPIO_Config();
$ |8 k; I) Y5 l& W2 {7 G - 14 KEY_GPIO_Config();
9 A. X( M4 g5 N - 15 //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M16 //HSE=8MHZ,PLL九倍频=72MHZ5 W; V m% r% S0 A. ^
- 17 HSE_SetSysClk( RCC_PLLMul_9 );
7 [" G; A8 V2 D! D5 U1 r - 18 //HSI/2=4MHZ,PLL十六倍频=64MHZ
6 \# v: Y& o/ w9 ~+ P9 }8 m8 w - 19 //HSI_SetSysClk( RCC_PLLMul_16 );) N1 W8 `5 _7 c' I& h" z8 [
- 20 ) P9 i( Q! P# K7 ?7 b, R) v
- 21 //MCO的GPIO初始化
; _. y+ \, O Y% X/ @8 V - 22 MCO_GPIO_Config();
5 `' R( \& B3 {4 B9 W: ^/ ? - 23 //选择系统时钟作为MCO输出+ p. f8 }, k/ U7 X+ p& v o
- 24 RCC_MCOConfig(RCC_MCO_SYSCLK); //PA8接示波器可见
* g! p- |% R1 |1 d - 25 //RCC_MCOConfig(RCC_MCO_HSI);
, D( n0 \$ g J" K - 26
% p5 ~" T J e0 L$ x5 r1 P - 27 while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化
+ w' j. H3 a- w, t5 { - 28 {
8 e" e: [# u2 q/ i2 Z' x& _ - 29 //8 U8 p$ g3 T0 V% t
- 30 //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON )0 Y8 ?$ F5 y5 Q) I Y
- 31 // LED_G_TOGGLE;
+ M1 ?6 N7 R J0 N2 s - 32
+ Z/ o- [% |# b7 `3 V+ R, G4 w - 33 LED_G(OFF);& y: j+ p! c. }: m# K5 \
- 34 Delay(0xFFFFF);8 |( P& s4 H' K2 U4 q% c
- 35 / w# S, m" _3 y8 L0 s1 d4 }
- 36 LED_G(ON);
( y Z X# Z" x# N6 \& n7 Q - 37 Delay(0xFFFFF);
6 ^5 F8 I) S0 t; | - 38 }
" S* P- |9 g6 _) R$ f ~! R - 39 }
复制代码
0 _# G, V. T# y+ y0 [6 f; T |