平时在做项目的时候都用的是外部晶振做为时钟源,想试试用内部RC振荡器做为时钟源,在网上搜了一下如何设置内部时钟,发现资料比较少的。决定将设置内部RC振荡器做为时钟源的方法记录下来。
) }1 T1 i6 a2 k$ m& E用的单片机是STM32F103C8T6,项目工程是在正点原子的示例代码上修改来的。用一个LED工程测试,在主程序中闪烁LED灯。7 ]( V/ u E3 d' w L H
6 O5 X: [- s/ S# p7 l- ?/ \1 {
- #include "sys.h"
4 r) \: ^# [: K' N1 a% j$ C - #include "delay.h"
) ]# R9 R ~9 Y/ a8 o" z& W - #include "usart.h"2 [! @/ i- O# A ~2 Z* U1 j. e: s
- #include "led.h"
3 Z1 c& j) B k - int main ( void )" @! I9 W: d4 c* z( Q% J" e
- {5 b' h5 D1 x- v# ?6 w
- delay_init(); //延时函数初始化
. ?' F5 x# D1 m; H2 o$ g - LED_Init(); //初始化与LED连接的硬件接口! D0 b/ `2 x# O. c' E
- while ( 1 )
9 R% { g2 F, W1 m. { - {
! d5 s( Y1 K! p% W5 l - LED = 0;2 f' y1 |: O& Q) W. y
- delay_ms ( 100 ); //延时300ms8 p# a) K3 `6 F3 b3 ?2 h4 u
- LED = 1;& L' @1 x- v+ c/ Y2 C
- delay_ms ( 100 ); //延时300ms( H8 c* y7 i V m( H6 }) x
- }+ M) w0 n" Z9 ]; V: p
- }
复制代码
2 W2 M3 B0 v, M" W, V1 T首先使用默认时钟设置,也就是外部8M晶振做为时钟源。LED灯灭100ms,然后再亮100ms。7 M F) H. G2 B4 d
下来看默认时钟设置的代码:
# N P, ` ]0 P: V在 system_stm32f10x.c 文件里面, SystemInit()函数设置时钟。
( k# x! H6 d8 |! Y/ U
4 L! l4 _" }" q+ {/ g- void SystemInit (void)
, r+ I& x0 T+ h8 k9 x0 J a/ N8 G% E - {1 ~/ }! p- W" a' m) `) [
- /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
" g2 ?$ ?$ c U* H2 [ - /* Set HSION bit */9 @0 o- }. Q. m8 @3 X, o
- RCC->CR |= (uint32_t)0x00000001;
% |0 U" B+ ? [8 D9 n - /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
/ M: u3 i; V5 A - #ifndef STM32F10X_CL
& f( K7 l, w2 m. f' {7 f - RCC->CFGR &= (uint32_t)0xF8FF0000;3 A/ ]3 w0 h3 V" `3 w
- #else5 W: v- D6 M% Y
- RCC->CFGR &= (uint32_t)0xF0FF0000;& Q, w1 S' ]6 H- o* y
- #endif /* STM32F10X_CL */' |& s, m8 {" W- E2 g. [, P* b" X
- /* Reset HSEON, CSSON and PLLON bits */
4 d2 X5 i1 O: l; C2 A - RCC->CR &= (uint32_t)0xFEF6FFFF;. L ?2 N8 ~* t# j3 V$ S4 }
- /* Reset HSEBYP bit */# N9 s' P) C/ m: Y& x& B6 }; G
- RCC->CR &= (uint32_t)0xFFFBFFFF;5 N6 k7 J1 ] b' P" G
- /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ N) p( h# S7 N" D1 \# N: \
- RCC->CFGR &= (uint32_t)0xFF80FFFF;
$ W+ x6 E o: f# E0 `. C - #ifdef STM32F10X_CL% R3 y. ^& \1 ^# m% v' Z
- /* Reset PLL2ON and PLL3ON bits */- x* T) M/ }( N* I z! B
- RCC->CR &= (uint32_t)0xEBFFFFFF;! P; `' Q/ |- K; q: ~3 c
- /* Disable all interrupts and clear pending bits */
" V6 R( c' V' p2 l( s - RCC->CIR = 0x00FF0000;# t5 u( Q. E4 L$ b+ O3 ?* l
- /* Reset CFGR2 register */
$ J4 Q7 o$ u) }( X! K$ g3 z - RCC->CFGR2 = 0x00000000;
) P9 A* }$ ~+ f/ f - #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
6 j; {. [7 _& |2 B. W5 o* w/ {0 ?& i - /* Disable all interrupts and clear pending bits */
3 q2 o% j: F9 D( I H4 K% x - RCC->CIR = 0x009F0000;
3 C1 M1 b. M+ I4 \" i% ?3 k - /* Reset CFGR2 register */& I5 O4 Q4 f) K" h% T C! P
- RCC->CFGR2 = 0x00000000;
! m: D- q: v) L& W9 a* ` - #else
( K0 b0 \( T, I9 q; K - /* Disable all interrupts and clear pending bits */
: B( R5 o) s5 u- @ - RCC->CIR = 0x009F0000;8 N" r: N$ o& i
- #endif /* STM32F10X_CL */
/ m2 j9 U" W3 \# d& ?0 h$ Y - #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
2 [7 P: l/ i. F' h1 Z( L8 j/ f) q9 t - #ifdef DATA_IN_ExtSRAM
- `# a& o* F6 Z* J. s - SystemInit_ExtMemCtl();
( m0 g# I( ]5 G( U( K - #endif /* DATA_IN_ExtSRAM */6 C N4 k+ |# p7 |
- #endif* M+ l- U% y$ v7 Z# v" H
- /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */$ v Y8 Y! x+ ?2 _
- /* Configure the Flash Latency cycles and enable prefetch buffer */9 B% h n# i: z$ u
- SetSysClock();
, g! _3 z3 {8 B- D2 z
. |- m9 X- L3 \8 T- #ifdef VECT_TAB_SRAM- \- Q* W! V# r7 O* W
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */7 L: I5 G) P; ?5 J
- #else7 x5 u$ P. r: }7 I) c |9 d) D. e
- SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
; ?/ o8 H: ?5 M y+ O: L& w; t - #endif9 F, V; o# ^- [2 v/ y
- }
复制代码
0 Q1 `4 i# Z9 Q; j# e2 M. T6 g如何要使用内部RC振荡器做时钟源的话,需要重写SystemInit()函数。设置代码如下:- /* 开启HSI 即内部晶振时钟 */; d- }4 [" ^: z& L$ X- I8 i* B
- RCC->CR |= ( uint32_t ) 0x00000001;" p, W. Z* F5 G0 {& K/ r2 s. _
- /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
# c7 B, k. e6 v. t7 C - RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;/ D1 z" ~+ m$ s' W7 F# U/ L' F8 R
- /*PLLCLK=8/2*9=36MHz 设置倍频得到时钟源PLL的频率*/
6 i Y+ ^) }' o - RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; //设置倍频后的频率
0 l% X' b1 o6 Z9 t% C6 P - /* PLL不分频输出 ?*/
! e r% T: x4 v6 |- P$ h) |# @ - RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;# t' R0 e$ I% M# F( ~7 }: y$ h# Q
- /* 使能 PLL时钟 *// `, F" c5 Z& b2 e7 m2 ?
- RCC->CR |= RCC_CR_PLLON;
: o& z, T7 S7 K5 t+ V - /* 等待PLL时钟就绪*/5 B! q. C4 [" \( ]5 b
- while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 ); l3 }6 ?5 _. o) h
- {
, c1 n' w$ J' [ - }$ M9 R' b( j4 Y' [7 ^0 J
- /* 选择PLL为系统时钟的时钟源 */$ m. X( ^3 _2 B7 d& ?8 i# O* N
- RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
6 W" D0 }( `: V; Y - RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
; o e. v- A% k+ s, W' n5 Y - /* 等到PLL成为系统时钟的时钟源*/
; F, y- ` z) Z - while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 ), U1 y0 h* [# t* t) H& K% C
- { }
复制代码
8 a! g" o. f$ V5 E% y! S' d( U为了方便和以前的代码兼容,这里使用条件编译来选择使用外部晶振或者内部RC震荡。代码流程如下:
% b1 k0 D* ]0 z3 @! ?#if USE_HSI3 `1 G: S% n: S q" K/ V' F2 N
{undefined r! {1 Y6 ~8 E& W
//使用内部RC
+ ~1 o8 M( `5 h- ], K/ L7 A4 U. N}3 G& A( b/ k4 [1 {, F" _7 }$ {
else
% l# v& D8 D) q+ j% P{undefined- f4 m( j- U1 b8 V+ L- }( X3 O
//使用外部晶振
3 Y# \/ N. W/ f7 f+ c, B}
. _5 f) ^8 `& d! \! c# W: G#endif
1 ~4 {9 s6 ]7 H/ G% B7 I8 K通过宏定义 USE_HSI 来选择时钟源,USE_HSI 为1时,使用内部RC做为时钟源,USE_HSI 为0时,使用外部晶振做为时钟源。5 K5 b- {& H3 z% I( l0 f7 }( y4 p
修改后的代码如下:2 h- H) x+ X0 V: T2 Y+ J' v. U# G
- 3 C$ l1 I+ C' a4 _- \& k+ S
- #define USE_HSI 0 // 是否使用内部晶振 0 不使用 1使用1 G y4 ^4 @ o* e% @3 h
- void SystemInit ( void )
9 j2 g/ @7 _4 N- k - {
6 H J, P5 G0 x, m* l( K/ @- n - 7 r4 H4 J! Q. L. E% h. a2 p" h
- #if USE_HSI/ d* Y s4 s: H5 D
- {
9 J2 G2 @+ R( E. ^. q8 } - //设置使用内部晶振% x0 O$ {5 e5 T4 ^9 r3 u8 \
- /* 开启HSI 即内部晶振时钟 */8 j$ c7 ~- I! s0 }5 Q/ g
- RCC->CR |= ( uint32_t ) 0x00000001;9 W z2 `- C9 `, Q7 r) e# k/ ^
- /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
: u' T; K. w8 a1 B5 W- y3 y: G - RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
" H' v6 T, o* {4 X( i - /*PLLCLK=8/2*9=36MHz 设置倍频得到时钟源PLL的频率*/: X# ^+ X3 {, k) H
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; //设置倍频后的频率; y. o5 w( r9 m. U! v# d/ a' @+ y
- /* PLL不分频输出 ?*/3 i' m" K; o+ ~* w* ^
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;9 o2 B, @. |5 R" p7 y6 [( \; m
- /* 使能 PLL时钟 */6 F8 g( d4 ~1 y* _& C" H
- RCC->CR |= RCC_CR_PLLON;
0 ?3 s3 K3 h$ o5 |4 K1 { - /* 等待PLL时钟就绪*/- Q1 h2 j* J% N* @' t6 Z/ f9 r
- while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
+ A g+ U1 A/ ]; ~) ~. w/ I - {. y! e4 {8 \9 P" K8 f
- }
0 g. w# L) e: L - /* 选择PLL为系统时钟的时钟源 */
# V' {; B2 s) P3 i - RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );) V$ e' G/ F9 y$ g
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;( w2 m @- h2 q; D0 \0 \
- /* 等到PLL成为系统时钟的时钟源*/
, |+ L3 o+ b* h0 ^( V: p. F/ X+ e - while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
9 i/ S1 n/ R" k( s: s1 L - { }' @ f4 e" g6 Z j
- }
2 G: K S5 e: z - #else, z( X6 y0 B' ^3 E
- {! Y* s' b: M+ Q) ?! n+ k. j- R
- //设置使用外部8M晶振
6 M) i. ]" j% P1 c, f1 Z - /* Reset the RCC clock configuration to the default reset state(for debug purpose) */7 I. m; G2 E0 B+ L
- /* Set HSION bit */7 }% y8 ?6 X! }2 x
- RCC->CR |= ( uint32_t ) 0x00000001;+ A6 t# f c, I- Y
3 q+ _, r4 u' n' b, f- /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
0 a- ^( w: @3 X7 y% d - #ifndef STM32F10X_CL8 f" A. X6 ?* @
- RCC->CFGR &= ( uint32_t ) 0xF8FF0000;0 w1 B+ O6 Y9 W! k4 H: C# S# q
- #else
7 B* v( M) I& c8 D( q - RCC->CFGR &= ( uint32_t ) 0xF0FF0000;
$ ~. P+ f& z: K8 d+ u5 c) @0 N& N - #endif /* STM32F10X_CL */+ a3 d: Q- r& g/ ^! A( I
- - x& A- q1 Z) T& Q* o1 T: G) i
- /* Reset HSEON, CSSON and PLLON bits */
2 \/ ~. J- g( d9 {/ y - RCC->CR &= ( uint32_t ) 0xFEF6FFFF;2 a2 ^' N# Y8 T' u
- 0 o6 j5 a) K- L2 f" N
- /* Reset HSEBYP bit */ X% e) _" b0 G9 d, i x
- RCC->CR &= ( uint32_t ) 0xFFFBFFFF;
0 R# L* |) `% C9 g# k! V# ?
) p0 O i0 W1 C$ u# u' `& }- /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
h! r% P! T2 y' Q - RCC->CFGR &= ( uint32_t ) 0xFF80FFFF;
, i1 G3 T4 _ _( g% ]" ~) T
6 O8 ], O% J) A7 b2 d- #ifdef STM32F10X_CL: Z, w3 A! G5 g
- /* Reset PLL2ON and PLL3ON bits *// Z9 b# J8 v2 h' _: }
- RCC->CR &= ( uint32_t ) 0xEBFFFFFF;% E2 s) H# h- F( u) i
- 5 P1 ~7 U, g% S. r7 ~+ n
- /* Disable all interrupts and clear pending bits */% K, S! {3 w! G. ?
- RCC->CIR = 0x00FF0000;
5 d+ J, `( i7 F: r9 w+ a
* B+ a& Q$ e+ H( Y' G. D- /* Reset CFGR2 register */7 e5 c" Q; [- [8 j/ e. M
- RCC->CFGR2 = 0x00000000;
3 p$ V" ]7 g7 ]% B - #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)' [6 S" E8 x$ p j% M; D
- /* Disable all interrupts and clear pending bits */9 \* f0 {2 M4 A1 g N
- RCC->CIR = 0x009F0000;
; b+ R5 W1 o) T; W+ a - : A8 y% ? H2 r) Y
- /* Reset CFGR2 register */9 {! f+ y* Y0 R' |
- RCC->CFGR2 = 0x00000000;
- A$ h4 |0 h5 |: I4 o3 l k - #else
/ @* O. {4 l7 u! H - /* Disable all interrupts and clear pending bits */
% w4 z6 [; y% S# N- h/ l - RCC->CIR = 0x009F0000;: D; p7 j& `7 r3 ~
- #endif /* STM32F10X_CL */
; `$ F8 X' U) s2 I5 Y( M& S
4 X. ]" \0 p, u, G8 q% k- #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
- Y' _' I' \8 C7 ]2 D - #ifdef DATA_IN_ExtSRAM5 j7 k% l4 @, i: K9 H( P. n3 z
- SystemInit_ExtMemCtl();) y, A$ ], }6 b! ~ t( T
- #endif /* DATA_IN_ExtSRAM */
# H; x7 P8 v# v- z - #endif
8 p& E' F, a5 X
" o. p7 L# c, E- /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers *// | E, |, |6 o2 C: L# [2 K; O
- /* Configure the Flash Latency cycles and enable prefetch buffer */0 v7 E+ l1 N7 W. D* E8 `, R
- SetSysClock();( H9 e2 |; T2 M8 l$ I' N- ]
, M l+ c9 c5 b1 N- #ifdef VECT_TAB_SRAM
% L' I8 L+ x7 @2 g ? - SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */% o1 \, q, B& R2 V, F1 ?
- #else
" ]5 f$ C, `* M6 z# C - SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */+ I% J% k$ w' [5 m, T0 I
- #endif# l8 [8 K& }% q$ N# `$ q5 K/ j
- }/ r9 f2 n. H$ W
0 s$ t5 d7 K) Z9 u2 K- #endif3 u/ ?7 E% _, S' Y4 B) R/ M- t
- }
复制代码
) g4 s- o- x6 ^+ ?内部RC默认为8M,将倍频数设置为9,这样使用内部RC振荡器之后,时钟频率就是36MHz。为使用外部晶振频率72MHz的一半。4 w% ^8 }3 k% [& U6 X
5 e! {$ |, {9 ], p) g+ r
- /*PLLCLK=8/2*9=36MHz 设置倍频得到时钟源PLL的频率*/1 H- u" n! b) x1 D& T/ J! \" P% U
- RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; //设置倍频后的频率
复制代码
- Q$ x, W) _" d: ~$ h3 D这时候在运行代码,用示波器测试LED的电平,发现是高电平200ms,低电平200ms。比使用外部时钟慢了一半,说明使用内部RC振荡器的设置代码是正确的。* Z2 G P& F1 j5 r' g
* C- z7 b6 r! p- ]9 Q1 c0 V2 D5 [
8 m/ ^1 |2 N3 `+ h8 K: T |