1 STM32的时钟源主要有:
6 u0 F' v. r" R4 H; B' D内部时钟* P, }) H) N+ |8 V( s0 Y" z* T
外部时钟
8 m5 g& d1 y7 w" G7 |锁相环倍频输出时钟
2 f; K! H/ N; G1 t
4 ~! Z8 r( d* o
1 b* w2 t' _6 `1.1 详细介绍
e) @1 _" @+ I0 t' a5 [$ GHSI(内部高速时钟); x+ y4 G& `1 _6 s* z. n
它是RC振荡器,频率可以达到8MHZ,可作为系统时钟和PLL锁相环的输入$ [5 z8 j: y% P3 o5 x9 P
* \9 W* T0 N9 a4 v b
HSE(外部高速时钟)% {, A1 u0 `' j) s
接入晶振范围是4-16MHZ,可作为系统时钟和PLL锁相环的输入,还可以经过128分频之后输入给RTC。( y8 B" V( C7 \& O4 t* I
8 | D# t/ z% w9 T6 I& z8 i
LSI(内部低速时钟)% t5 ?: S1 O" C' E4 y
它是RC振荡器,频率大概为40KHZ,供给独立看门狗或者RTC,并且独立看门口只能依靠LSI作为时钟源
2 c9 B$ I+ V8 @- W" ~
# r, Z& U: u2 Q# ~0 ]1 Z3 K: \3 ?LSE(外部低速时钟)
* x! E" V. W' X. F, ]$ ]! p/ S通常外接32.768MHZ晶振提供给RTC* J$ p/ Y* P- T) P" W
! Q. N$ j2 A+ C4 a
PLL(锁相环)+ y) J. ]- d. u8 f* k+ ?
用来倍频输出。因为开发板外部晶振只有8MHZ,而STM32最大工作频率是72MHZ。他可以通过HSI输入,HSE输入或两分频输入,通过PLL倍频(2-16),倍频之后输入给系统时钟。& `- {1 h+ V$ s) P7 n6 ]
" [# N5 r. u9 n9 I7 x3 m+ K
MCO(时钟输出管脚)+ t4 I9 ^/ q5 u/ f0 K9 B; Q. t
通常对应STM32 PA8,它可以选择一个时钟信号输出,给外部的系统提供时钟源
' i( g3 L6 x9 j+ P4 E* }
0 I1 \; \# {5 O) `2 标准库的时钟配置# z2 K& h7 }; u9 D. b
2.1 STM32启动文件
& n# L E8 }9 b$ V6 R/ c9 ^首先打开startup_stm32f10x_hd.s,该文件为stm32的启动文件,在该文件内会发现有这么一块用汇编写的代码。
# @$ h% i. a+ u3 T; `* c1 [- Reset_Handler PROC& ^) |* h6 ?! [+ x: i) n
- EXPORT Reset_Handler [WEAK]
8 |. ?" n. `3 z4 k3 l8 G - IMPORT __main
- f8 m, l* p) q, h+ J - IMPORT SystemInit3 I8 B5 s2 ^4 [7 c9 U
- LDR R0, =SystemInit
! m9 {' F( @; B( {- a5 F - BLX R0
! Y" w7 v# @) @. Q2 {2 g* b - LDR R0, =__main
7 a, g: r) K( m - BX R0) a0 l0 {4 a+ F& K0 Z" c: n6 m
- ENDP
复制代码 5 H5 `1 F8 ~2 u- ~7 z8 T
通过这段汇编代码可以看出,程序在执行main函数之前,会先执行SystemInit函数。* b& U3 J& v" g& C8 [ O9 a
1 |5 K, A$ m0 c2 e0 p9 @2.2 SystemInit函数详解- void SystemInit (void)' h+ r+ `2 R+ f3 V) y
- {
' r+ ?( |, V% |5 q - /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
% n9 }6 p6 A \0 V - /* Set HSION bit */
; m1 |. J4 Z0 ]6 Y( M. ~ - RCC->CR |= (uint32_t)0x00000001;: M+ w( P- n- e, Y5 ~# E# @$ c
. {7 w n+ U5 d" |6 b$ S9 B3 }- /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
- P9 x/ L1 P5 q Z - #ifndef STM32F10X_CL
( Y; o& ~& C3 n+ n" V! g2 E - RCC->CFGR &= (uint32_t)0xF8FF0000;
$ Z) }1 q$ b1 A5 u, P - #else" Q f4 k. c k7 M! b
- RCC->CFGR &= (uint32_t)0xF0FF0000;
0 n: V* U. ?1 ]) V. _5 C0 a - #endif /* STM32F10X_CL */ 4 N. d1 I1 h/ ?/ B b# ?/ h% k7 k
- ; A0 g5 R+ V _1 C9 o6 u
- /* Reset HSEON, CSSON and PLLON bits */
8 e" K6 H+ ]9 ]8 }4 @; h - RCC->CR &= (uint32_t)0xFEF6FFFF;
1 L4 W6 Z6 z3 f4 X2 x
5 d3 s0 _$ e7 Y0 e" o- /* Reset HSEBYP bit */
2 a. ?$ h6 y; N - RCC->CR &= (uint32_t)0xFFFBFFFF;0 y1 P, y9 ]$ f; N
$ e: Y' p6 m8 ^, j8 G/ z' T- /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
r, g9 q6 q- Q, J - RCC->CFGR &= (uint32_t)0xFF80FFFF;
" O4 ~% m5 ]) a; O% W* m4 Z - ! h8 V# R+ t* N0 s! Z' X5 t
- #ifdef STM32F10X_CL
3 F- D4 z8 x: E - /* Reset PLL2ON and PLL3ON bits */
7 A8 }+ { v0 A1 F5 V) V n- u - RCC->CR &= (uint32_t)0xEBFFFFFF;
8 w7 |, C& }6 O% w, e - % I) q/ F7 N" R7 X
- /* Disable all interrupts and clear pending bits */
7 n# H/ L7 _; ? - RCC->CIR = 0x00FF0000;
& R% g+ K. @5 z9 c; Y9 q/ u
! m- C( F$ ]/ i' G2 P, f) v- /* Reset CFGR2 register */
% C; g6 f l+ n0 l8 [8 c2 _% L - RCC->CFGR2 = 0x00000000;- |0 Q( P. Q; U4 N- k5 h t3 M
- #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)% Z, w f" B* }) q6 X
- /* Disable all interrupts and clear pending bits */
5 O5 _0 ]/ }5 y9 } - RCC->CIR = 0x009F0000;( i' o7 I) C3 L* K# M: S9 w4 {7 E
" s5 D, k' ]! T# Q9 C! I! T$ C$ m- /* Reset CFGR2 register */, P* w5 M4 R' o( J+ o1 m3 K$ E
- RCC->CFGR2 = 0x00000000;
* i0 u- _" u7 W0 E G( \6 g - #else
2 O& H" H1 R r. r1 y, J8 D8 i - /* Disable all interrupts and clear pending bits */
' z; j, O3 C! d( X5 e - RCC->CIR = 0x009F0000;
- P- `0 T9 a3 t - #endif /* STM32F10X_CL */6 T, r( x; A2 \7 r
- , e8 A1 A% {0 {6 a6 d( ^9 N9 j: \
- #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL): b# o- T, d& y0 x1 @4 N
- #ifdef DATA_IN_ExtSRAM
0 D) w3 b- V n1 P - SystemInit_ExtMemCtl();
: V& o! Q$ }, v; v7 J. b - #endif /* DATA_IN_ExtSRAM */' m/ Y( O2 A5 Q
- #endif 2 E! O; N4 q" y5 W: p( B7 q. i
9 b, x" `2 o" ^7 Q3 T) T* @, T1 `& m7 s- U- /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */ G# |% [- K; G/ C' t9 i; B
- /* Configure the Flash Latency cycles and enable prefetch buffer */
) a# A4 {* N/ U - SetSysClock();
+ N4 [& N+ J# _4 u* F$ s
3 M |5 H% |$ @2 h( i9 ?- #ifdef VECT_TAB_SRAM
% z2 {5 ?3 a/ r* D- n& U& ]( \ - SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
1 X! H/ h6 I# G; `- E( N0 O - #else
5 X, m: P6 K# o9 M - SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */' B7 Y+ N0 |6 d2 I8 U. X% V6 B2 B$ L
- #endif " Q+ \% o! n8 S2 U# X7 Y r6 g; O
- }
复制代码
' ^1 |. `9 }$ l. G0 c$ V5 {, @7 ^ w" ^: G( L0 o0 T9 K
打开内部8M时钟:9 I3 P5 T5 T: R5 Y. X
- RCC->CR |= (uint32_t)0x00000001
复制代码
9 t2 G1 d! F9 @通过查看寄存器手册可知,这段代码为打开内部8M时钟。% h8 c3 e) E$ p
* V2 a! d8 n: d
6 k* [1 [* j u, @
# ]# U3 M6 Z$ F2 ^; n \4 R" t设置时钟配置寄存器:$ Z5 C4 {& Y# N$ O0 _: D$ m) H, {. z
- #ifndef STM32F10X_CL1 U) P* C H9 _' m
- RCC->CFGR &= (uint32_t)0xF8FF0000;
- ?) P" E( B- W& u - #else" i* w3 S4 A/ q( e8 c
- RCC->CFGR &= (uint32_t)0xF0FF0000;
6 {- |; P0 V/ x" z1 _( K! P - #endif /* STM32F10X_CL */
复制代码
3 S9 }7 a9 s2 U3 w# T对应寄存器说明可查看《STM32中文参考手册_V10》的6.3.2 时钟配置寄存器(RCC_CFGR)章节。
* B( z* h2 }, l. s) }: k后续代码,有兴趣可根据《STM32中文参考手册_V10》手册,查看代码具体作用。
; ^4 L$ l, |5 L, A
/ q# S8 Y/ i0 j! l2.3 SetSysClock()函数详解
6 s1 u. K6 F- N, G4 Z- static void SetSysClock(void)7 P* a5 A5 f8 A1 V$ u/ }
- {6 Y/ u1 ]; e- |9 n+ a! P" k! e5 `
- #ifdef SYSCLK_FREQ_HSE
# q6 ?* H- }' s4 X6 l - SetSysClockToHSE();9 w+ ^' k- A. P9 ]' _
- #elif defined SYSCLK_FREQ_24MHz
/ ~& d3 {0 g; q N9 J - SetSysClockTo24();
6 Y3 c: [4 Q- Z0 X; V a7 j - #elif defined SYSCLK_FREQ_36MHz
/ h* b( _! V0 C8 N' F - SetSysClockTo36();0 Q/ t# ?4 [& k- F# y! u. k- |
- #elif defined SYSCLK_FREQ_48MHz
2 }/ L0 p) u; B# C2 q# ~9 e- J - SetSysClockTo48();
, y5 N7 s# E' I0 X - #elif defined SYSCLK_FREQ_56MHz% \; q7 |- x5 B! O- w$ [/ \+ M
- SetSysClockTo56(); ' z4 B0 I0 `% M0 q* L" ~* O2 W
- #elif defined SYSCLK_FREQ_72MHz, Q' j1 ?" p2 l& \/ n" Z/ E
- SetSysClockTo72();
- F/ `" K7 ?- [( N) q% z: m! J% i" _7 n - #endif
: M0 |& O8 a! B& S' c - }
复制代码 5 L* d c3 d/ Z) b- k' z, G' z9 |" }4 x, b
: L3 i9 e8 J5 z0 hsystem_stm32f10x.c文件中会根据芯片的型号定义对应的宏:/ G ? y) {. q, n
- #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)$ T' Y3 @: p2 r6 {$ v& e+ x1 d9 S
- /* #define SYSCLK_FREQ_HSE HSE_VALUE */! c7 U G+ n6 ^0 l, j
- #define SYSCLK_FREQ_24MHz 24000000
, c! i+ ~; f) x6 F& M - #else* g: A3 V* j% p& U1 p2 P3 K
- /* #define SYSCLK_FREQ_HSE HSE_VALUE */
8 K2 f7 l" J( G0 [9 r' q" Z - /* #define SYSCLK_FREQ_24MHz 24000000 */
0 z8 ]6 L8 T$ M' K9 p - /* #define SYSCLK_FREQ_36MHz 36000000 */! a6 l. Y3 B3 G y- t/ k
- /* #define SYSCLK_FREQ_48MHz 48000000 */: {8 z/ c" x# P3 P
- /* #define SYSCLK_FREQ_56MHz 56000000 */2 w! o2 Z2 y# f: z+ p, j
- #define SYSCLK_FREQ_72MHz 72000000
& I5 L" z. ], [ - #endif
复制代码
; N; _7 w" |, }8 Y3 时钟配置函数8 X* [5 M1 a u, G+ U. k. B% c' `
3.1 时钟初始化配置函数- void SystemInit(void);
" e) M4 r8 p ~- O8 @1 M S7 a6 I - SYSCLK(系统时钟)=72MHZ;
, Y2 Z% k4 A+ G. l - AHB总线时钟(HCLK=SYSCLK)=72MHZ;
& Y3 F7 x' U1 c& S4 e9 i - APB1总线时钟(PCLK1=SYSCLK/2)=36MHZ;* e" A9 ]' `, n6 H) `9 v
- APB2总线时钟(PCLK1=SYSCLK/1)=72MHZ;
* J7 T9 v7 Y4 g6 } - PLL主时钟=72MHZ;
复制代码
# Q# W6 j. U0 y' m& O
- J2 @: E! [4 C( P3.2 外设时钟使能配置函数
9 z- ]( k5 h4 J' x- void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);, u% {+ V4 `1 J& z5 F) G
- void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
0 v. I( O* b- G1 z4 T+ f& z - void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
复制代码 . N5 b2 X" O0 o$ o
3.3 时钟源使能函数- void RCC_HSICmd(FunctionalState NewState);
D" q6 \% R, ~+ X ] S2 o - void RCC_LSICmd(FunctionalState NewState);1 i& C' P8 j8 G) C, L l. B" w
- void RCC_PLLCmd(FunctionalState NewState);
2 w4 g( K% U% _. l8 V - void RCC_RTCCLKCmd(FunctionalState NewState);
复制代码 9 G* E4 M' p8 e/ O
; v$ _! v% ?! z1 b. c2 \3 c3.4 时钟源和倍频因子配置函数
0 ?' V' r5 A3 {# d' N& o# T9 r- h- void RCC_HSEConfig(uint32_t RCC_HSE);# B; Z8 J) ?9 o! W `0 N. Z: _
- void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);4 C5 Z. D5 T+ B
- void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
) s6 X" c. X+ f- p - void RCC_PCLK1Config(uint32_t RCC_HCLK);
* J- {, a0 P; ^' f - void RCC_PCLK2Config(uint32_t RCC_HCLK);
复制代码 * @5 a$ V7 i3 N+ o2 T5 @7 z9 K" b: p
3.5 外设时钟复位函数
! e$ r7 a$ h7 c& K, _7 v8 t- void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);, @6 }. i2 r1 S& n0 _0 M/ w1 l" B
- void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
复制代码 # s1 ?) C/ }$ T9 X1 \; E$ O2 G7 Q
3.6 自定义系统时钟8 h' x5 T4 l* T6 c
- void RCC_HSE_Config(u32 div,u32 pllm)
2 s( P; W; m( r; V9 p, h8 W - {% P6 W7 l$ a1 D9 i$ F3 w9 X! A" g
- RCC_DeInit();6 k4 J; C' J( S" m( a
- RCC_HSEConfig(RCC_HSE_ON);
7 S% K6 l# m* t* h2 U - if(RCC_WaitForHSEStartUp()==SUCCESS)
$ G" |+ a n, I7 V$ v$ c- l9 p - {
0 H8 C' l1 q. R: U- } - RCC_HCLKConfig(RCC_SYSCLK_Div1);
% D3 P% M* w4 D* l" x - RCC_PCLK1Config(RCC_HCLK_Div2);+ Q2 ~; d6 F6 s( H* w9 h
- RCC_PCLK2Config(RCC_HCLK_Div1);
$ T r1 i1 _% d& k! Q1 C - RCC_PLLConfig(div,pllm);% S" _ @% a' V$ F. D
- RCC_PLLCmd(ENABLE); 1 U' o4 i* {' V5 o
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
3 s; h: f" d% D8 T. c - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)( M2 J; d; s1 m0 ?* k
- while(RCC_GetSCLKSource()!=0x08);% M) L0 Z# J( {! i
- ( t( z) c8 Q' X6 C0 B) q" A7 p+ {
- }
( O& L/ O( `# G( {5 M - }
复制代码 转载自:STM32嵌入式开发
3 ]# {) `8 y" z" t+ }( @& @" G& y$ ~# t1 s, W, S. x: h
如有侵权请联系删除
) K) q. Y" F% C
3 `( [% ~* ^3 f7 C |