平时在做项目的时候都用的是外部晶振做为时钟源,想试试用内部RC振荡器做为时钟源,在网上搜了一下如何设置内部时钟,发现资料比较少的。决定将设置内部RC振荡器做为时钟源的方法记录下来。
4 I$ R/ X6 h9 K用的单片机是STM32F103C8T6,项目工程是在正点原子的示例代码上修改来的。用一个LED工程测试,在主程序中闪烁LED灯。
" i$ f2 | \" n s: ^$ q6 \6 ^) u9 C3 }5 e8 O# }
- #include "sys.h"4 R; s) G9 u. E" `# R8 K/ O
- #include "delay.h"/ {. O M! ]9 Q" T D @" U* Q
- #include "usart.h"+ X5 p. `) B! G+ G
- #include "led.h"+ F' P% n3 U8 G( L# g% _
- int main ( void )2 s( n2 f% b" X" ]( a3 f& P5 E
- {
- R7 a+ J' `" @& z1 | - delay_init(); //延时函数初始化
: [, H' u! o7 U: V2 y( h - LED_Init(); //初始化与LED连接的硬件接口0 V5 a% R' U9 V0 S6 r& M0 h( f
- while ( 1 )
* u/ y0 h/ B& E" m: C - {
8 Q5 u' Z- k# F. F1 m - LED = 0;
+ F6 P9 d4 @! m W; z3 G4 j - delay_ms ( 100 ); //延时300ms
* V* \; ^& X2 s( l% ]- ~) S+ a - LED = 1;$ f( X3 y6 r+ Z
- delay_ms ( 100 ); //延时300ms; O7 Q1 L% |4 g' H
- }
. B9 h6 b- z4 G6 C | - }
复制代码 & M, j9 n8 s* q8 n {% v
首先使用默认时钟设置,也就是外部8M晶振做为时钟源。LED灯灭100ms,然后再亮100ms。) \7 `2 J* a! u0 s; a; w5 r- |, k
下来看默认时钟设置的代码:5 {9 ]/ y3 _$ z4 V' H* F' f
在 system_stm32f10x.c 文件里面, SystemInit()函数设置时钟。6 G- K! ]5 l6 l- x g$ z
3 c2 x4 E' s& Z, T. x0 i- void SystemInit (void)8 b, {) r. t, t6 N
- { W, ~$ r$ z5 D1 q- Y- C1 X
- /* Reset the RCC clock configuration to the default reset state(for debug purpose) */6 T4 p3 N$ A: r& S1 K7 s8 ]
- /* Set HSION bit */9 z7 k0 ?* N) C- c* d; l, |
- RCC->CR |= (uint32_t)0x00000001;
& G! Q% `, ^# W) f# l; O- k - /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
" L* o" l* k: L, N+ L - #ifndef STM32F10X_CL
/ j1 w. {8 m/ K2 }2 x1 } _9 R - RCC->CFGR &= (uint32_t)0xF8FF0000;! u$ U3 I0 z1 r! B7 U
- #else% f$ E1 W3 _& I
- RCC->CFGR &= (uint32_t)0xF0FF0000;1 t0 J" |, ^4 @+ [ D
- #endif /* STM32F10X_CL */
7 Z* O- e! ?! Q9 ~9 p- o - /* Reset HSEON, CSSON and PLLON bits */4 e/ S" z; v& n5 H( w
- RCC->CR &= (uint32_t)0xFEF6FFFF;
m; I4 E4 ?) z% c$ v4 o - /* Reset HSEBYP bit */
9 B7 D$ O3 I$ C2 W9 K3 \. b3 w9 S3 T - RCC->CR &= (uint32_t)0xFFFBFFFF;
) ?/ `9 e7 W+ Z0 @; L: C - /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */8 ?% N, y/ Z1 u1 j+ \( z
- RCC->CFGR &= (uint32_t)0xFF80FFFF;' @/ ?- d; @" |+ X
- #ifdef STM32F10X_CL
9 s* x; g- Y$ m J - /* Reset PLL2ON and PLL3ON bits */& y# g2 n7 |# U8 `
- RCC->CR &= (uint32_t)0xEBFFFFFF;
# j! ^- c, |) I7 X# L) G' A - /* Disable all interrupts and clear pending bits */
* a7 z+ K& i8 Q8 g - RCC->CIR = 0x00FF0000;. X; e0 B# x7 p3 ]" D5 Q$ g
- /* Reset CFGR2 register */
" S& d8 M I0 L; a& u6 y - RCC->CFGR2 = 0x00000000;- Y$ G! H* ]: W, ~, O7 u
- #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL). Q3 M( l. ?+ Q
- /* Disable all interrupts and clear pending bits */ p% j2 F& b/ C* c* X; C. G7 ~, B+ ^
- RCC->CIR = 0x009F0000;$ L* N2 k' z, O, ?
- /* Reset CFGR2 register */
4 N3 A+ ?. Y" E; L - RCC->CFGR2 = 0x00000000;
3 S0 [2 ^1 i+ N6 {# w - #else
/ H: y. S! ?# D7 U* R - /* Disable all interrupts and clear pending bits */
5 I) R; i. t- B- e - RCC->CIR = 0x009F0000;+ [9 v6 m3 X3 W( }/ A/ ?- G0 c
- #endif /* STM32F10X_CL */
4 ?$ b) C6 o: u& ^9 R8 n - #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)& d: t+ }4 K# @1 k$ R3 i# O; Y
- #ifdef DATA_IN_ExtSRAM. }# U1 X/ \% q+ [9 ^ l
- SystemInit_ExtMemCtl();6 b& ?/ Y& d6 \( C9 M5 f8 d
- #endif /* DATA_IN_ExtSRAM */
% m; t; Q2 a% L+ O5 c/ A - #endif
$ D& ?" @! f# x4 ?' Q& I - /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */1 L4 `$ T) I) Y: d
- /* Configure the Flash Latency cycles and enable prefetch buffer */( ?" W, W2 J# M7 y+ {
- SetSysClock();# Y9 i J$ T2 L3 l/ r& T2 K
- ! B8 L5 v) ^; o, h% V+ Y/ b
- #ifdef VECT_TAB_SRAM }" C! g) n& \. q8 l3 `# f
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */9 ^8 R Q/ `( M0 \
- #else# E5 E8 l+ [8 A2 l- k2 \
- SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */3 S5 ^) c- {0 B, B% u/ A
- #endif
7 C* j4 u6 a' j0 ^ - }
复制代码
" ^' V3 u( w w. w2 e如何要使用内部RC振荡器做时钟源的话,需要重写SystemInit()函数。设置代码如下:- /* 开启HSI 即内部晶振时钟 */
P' Z1 N6 ?2 ~. S5 b, d( X, X - RCC->CR |= ( uint32_t ) 0x00000001;! o9 P7 m6 ?$ I* o
- /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/. ]: X- U/ q. x( u5 G7 G
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;$ D! [- S0 s$ q+ Y
- /*PLLCLK=8/2*9=36MHz 设置倍频得到时钟源PLL的频率*/, O9 d" |/ F6 c1 J/ Q
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; //设置倍频后的频率2 e$ y$ G, {3 r# G
- /* PLL不分频输出 ?*/( i; z! |1 |0 B6 Q% A* _: f
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
: `3 o. _/ ~0 E; J - /* 使能 PLL时钟 */
& q/ d6 L4 B0 H6 I9 f9 t% d - RCC->CR |= RCC_CR_PLLON;. q1 t# n, I( `- G) u T4 M* }, A
- /* 等待PLL时钟就绪*/
) D( w3 s( p; t* g8 P! _ - while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
6 k- r: T6 d+ D; `' z4 W - {
7 u! K- j4 u/ I) S6 A; b8 D! e, N - }, p, G! l+ T! z0 r
- /* 选择PLL为系统时钟的时钟源 *// o" ?' t; h/ N
- RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
+ q/ a) C* F" D$ x9 f - RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;+ A' q6 s' h1 T; G1 \
- /* 等到PLL成为系统时钟的时钟源*/& M- K% ?0 A* B3 R/ T
- while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 ): ~* z1 a9 s& u
- { }
复制代码
3 q4 o9 F. E4 i' c1 p! a为了方便和以前的代码兼容,这里使用条件编译来选择使用外部晶振或者内部RC震荡。代码流程如下:2 W5 E# k: d9 R/ H
#if USE_HSI! _7 M8 e1 C& U
{undefined
0 x4 t+ S+ t: @. }( ~9 N3 Q//使用内部RC
& I' E( W0 I; c}
) N6 c' X) i2 T1 eelse
% x$ z# ?% _' f5 V5 K7 F. T) u2 I: t6 }{undefined) J" v7 z2 m8 S3 c
//使用外部晶振
2 }' j% ~1 i0 P2 ?6 [8 ?7 }8 l}
7 y A, `& S5 m* D3 D+ ?9 ?#endif
2 Y, q9 c2 z! B通过宏定义 USE_HSI 来选择时钟源,USE_HSI 为1时,使用内部RC做为时钟源,USE_HSI 为0时,使用外部晶振做为时钟源。
4 L7 I$ x' H/ y( U1 q修改后的代码如下:& }0 X3 k3 X: P) l% h! P
- 4 `( P9 L; T, d, Z2 o3 a8 _
- #define USE_HSI 0 // 是否使用内部晶振 0 不使用 1使用' v6 [7 L! U1 o% w6 O# P1 A
- void SystemInit ( void )
* @# t* d1 ~1 L% ~9 R - {
c# [8 ~5 c. h m2 X0 P* O! @
7 ?9 W" w6 b/ O) R) U5 ?- #if USE_HSI
# m4 Z3 M4 L2 Z' @7 U, p/ g3 a - {9 g3 f# K, X" I0 I
- //设置使用内部晶振1 V# o' i- P7 p# m- U: L
- /* 开启HSI 即内部晶振时钟 */7 B, g# X& R" X
- RCC->CR |= ( uint32_t ) 0x00000001;
# Q: V9 L2 }+ i6 |+ _6 |9 H - /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
' b1 Z* S6 s) p, F) m0 q - RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
( x0 ^- h! M. y- D8 r - /*PLLCLK=8/2*9=36MHz 设置倍频得到时钟源PLL的频率*/' |% _5 K$ D4 j9 `6 F/ _
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; //设置倍频后的频率
7 a# ]# H- ~% W/ _# E - /* PLL不分频输出 ?*/+ C5 ]4 r2 b( d" z' ]/ u. q
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;; }# S- T A" N& a( W
- /* 使能 PLL时钟 */
8 N5 ?5 l. U2 u2 p7 X - RCC->CR |= RCC_CR_PLLON;- P$ K/ p, W. X( k3 @8 x
- /* 等待PLL时钟就绪*/6 c' [5 _% R$ w! O
- while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
* a% q" U1 h% p. X9 P, J% o - {9 P. r# S9 B* [ y7 b: I" }0 q
- }
8 A. K/ x' y4 @ - /* 选择PLL为系统时钟的时钟源 */& c3 L7 d/ d. L( L2 n
- RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
! p0 o I. Q2 L I- z: C8 A A7 [' C - RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
' P) Q) v" D4 u# T1 P% u" A( i8 Z' u1 b: T - /* 等到PLL成为系统时钟的时钟源*/
, b* B; o; K i3 z4 p7 b5 ~- Z- D - while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )4 a, i( X1 X7 w. x9 ?1 {: m
- { }3 b+ @" l) D5 p/ z5 n
- }: g5 H, Q* |7 ?) s# I) r" A2 [
- #else
. f, L: r1 V `' d" _6 p - {
9 [5 o$ q9 Q" q; r2 I - //设置使用外部8M晶振7 U7 }; o& B- h' X! a; _# u) x
- /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
5 w" q. B+ f: |3 n9 [- w3 m3 r - /* Set HSION bit */
; H0 S6 V6 a% F) o7 N% J - RCC->CR |= ( uint32_t ) 0x00000001;
( {0 ]- ~0 Y6 F4 b: u& ~$ v5 Z - * H' W1 `8 l3 F- P$ A; J1 c
- /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
4 H }" Q0 i+ R0 Z& P5 L - #ifndef STM32F10X_CL7 i, j2 ?- g9 {& g% A3 \# B* n
- RCC->CFGR &= ( uint32_t ) 0xF8FF0000; @0 u1 F( d5 G) k# B
- #else
- w/ _- x$ }# s. [2 W - RCC->CFGR &= ( uint32_t ) 0xF0FF0000;* z$ A. {5 `/ K& K6 c8 v
- #endif /* STM32F10X_CL */
; T# H2 Y. I# _: F; ~ - 3 }+ }( Z) \* C& G
- /* Reset HSEON, CSSON and PLLON bits */
. K& v4 p1 v! P/ l - RCC->CR &= ( uint32_t ) 0xFEF6FFFF;' `7 `0 C4 a5 I! I. P
) p$ s2 W4 z6 t! b5 N- /* Reset HSEBYP bit */: z: ?7 C6 Y. e3 A& @3 j0 E. t
- RCC->CR &= ( uint32_t ) 0xFFFBFFFF;
7 \3 ]0 e( I ]& L! _8 S
6 F5 F: N& b I( [& j3 x- /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
* c( G" }, Z1 F! d5 L4 Q - RCC->CFGR &= ( uint32_t ) 0xFF80FFFF;# h1 U1 N: U- ^, ~) M
9 }$ z, ~, {* ^# K! ]$ a! h; v- #ifdef STM32F10X_CL" Q. }# B! ~& o: R9 \+ H
- /* Reset PLL2ON and PLL3ON bits */3 N+ _! O" D+ | w
- RCC->CR &= ( uint32_t ) 0xEBFFFFFF;
) W9 S2 f% Y$ l" b5 |0 C - 0 |! T0 R# D7 G. P' r
- /* Disable all interrupts and clear pending bits */, u' g' C8 O5 f' e+ }+ z
- RCC->CIR = 0x00FF0000;8 D$ S4 X) i/ c( A8 ?) s, `
, R3 H" {- a4 q/ N- /* Reset CFGR2 register */
! @. B* U& c& @6 T5 v - RCC->CFGR2 = 0x00000000;
" r( _9 Q/ p* v6 g; N0 ~6 v - #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
8 w$ y' f" J: s8 w& y - /* Disable all interrupts and clear pending bits */5 V9 \' p% Z+ W
- RCC->CIR = 0x009F0000;
5 ^- T/ Y" w# J9 i2 j - . Z+ C3 `" e" C) J; W& o- }! f: l. ]
- /* Reset CFGR2 register */6 w$ `; m, Q; w
- RCC->CFGR2 = 0x00000000;
. [* q0 q; X( q) U( B$ \9 b% C - #else: n$ K* ?% T$ d1 `
- /* Disable all interrupts and clear pending bits */9 Z; i/ r6 z9 K2 A6 G8 ]' _0 g. [
- RCC->CIR = 0x009F0000;
Z6 q3 f% T7 h: r- ~/ G - #endif /* STM32F10X_CL */! A: r$ f: y# l* j B# q3 o9 c
. R$ v3 A! _: K. A- #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)8 k1 ~+ ]/ `8 Q8 U% M. ]
- #ifdef DATA_IN_ExtSRAM
4 i: f: t2 w3 O/ g6 ~; N# w - SystemInit_ExtMemCtl();
9 T* z, F. u# E - #endif /* DATA_IN_ExtSRAM */
H4 C( {7 B S2 g. n9 \: B - #endif
7 V, ]) R. q- x- @- z
# t0 [2 p/ X3 B2 O$ }) w- /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
" E1 ?4 Z2 B2 L9 D# h - /* Configure the Flash Latency cycles and enable prefetch buffer */
' W! G+ h h1 h5 b - SetSysClock();
9 z5 Q: p2 w$ } - % i g3 V' u3 l6 D) ^' h
- #ifdef VECT_TAB_SRAM3 R7 L6 N3 R# N, J
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
+ |9 J4 T) n; h% a" S+ \# y - #else
$ W' Q+ [) {7 c7 @6 M* V - SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */& l. T8 I# l) o% W# v
- #endif
0 E3 \ c9 c# q; h A - }5 H% K" C$ A/ z2 P |
- 3 a6 F( v: l5 k! h( ]7 b2 [
- #endif
S3 f% O: |. C8 n5 s - }
复制代码
, u" q# r* Z& u" n0 z内部RC默认为8M,将倍频数设置为9,这样使用内部RC振荡器之后,时钟频率就是36MHz。为使用外部晶振频率72MHz的一半。7 z- n9 a1 Z) Y9 {6 J
+ b) O# u8 b0 e5 I
- /*PLLCLK=8/2*9=36MHz 设置倍频得到时钟源PLL的频率*/* U8 T/ a( U( [: P
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; //设置倍频后的频率
复制代码 & f% X$ f& d) d
这时候在运行代码,用示波器测试LED的电平,发现是高电平200ms,低电平200ms。比使用外部时钟慢了一半,说明使用内部RC振荡器的设置代码是正确的。: U' [$ ]0 E P
2 T) G2 u, V) u: |5 S7 B
6 b: a5 R" r2 {. M |