你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103单片机使用内部RC振荡器做时钟源

[复制链接]
STMCU小助手 发布时间:2022-3-22 13:00
平时在做项目的时候都用的是外部晶振做为时钟源,想试试用内部RC振荡器做为时钟源,在网上搜了一下如何设置内部时钟,发现资料比较少的。决定将设置内部RC振荡器做为时钟源的方法记录下来。
: y# U! k1 O, {$ g用的单片机是STM32F103C8T6,项目工程是在正点原子的示例代码上修改来的。用一个LED工程测试,在主程序中闪烁LED灯。
! V  r+ N) S, }! {' N$ U1 j* _  q( X+ q: Y9 M' g9 }" U7 o  [
  1. #include "sys.h"1 L) e5 i& J/ i& N2 l2 R' U
  2. #include "delay.h"7 Z6 o1 b& U) ]4 j+ W
  3. #include "usart.h"1 G0 m( a" ]+ y# O1 F2 H3 {( R
  4. #include "led.h"1 [5 I, Q+ Y2 L* r
  5. int main ( void )% S+ E" |* C) N  o0 v! m. j
  6. {! [8 I* t' t" A' A; K
  7.     delay_init();       //延时函数初始化# \& ]9 E* O2 D2 L/ t
  8.     LED_Init();         //初始化与LED连接的硬件接口
    & A- I% M. Y4 N, W7 u  p/ o, V, G
  9.     while ( 1 )& d/ D, I4 k( z- L: B
  10.     {
    , d8 A3 C9 c3 I  ~, V
  11.         LED = 0;
    ! q$ R6 n* _9 c, @& `
  12.         delay_ms ( 100 ); //延时300ms, D" F* ~, W. x
  13.         LED = 1;' P( u# \. J: w" T+ H7 O
  14.         delay_ms ( 100 ); //延时300ms  T3 @0 q# K) J+ L5 N: H
  15.     }5 M6 Q! [* b! Q' i
  16. }
复制代码
/ B3 h) ^9 _  w9 [8 p! |
首先使用默认时钟设置,也就是外部8M晶振做为时钟源。LED灯灭100ms,然后再亮100ms。$ m3 y7 Z" r' \3 [
下来看默认时钟设置的代码:
7 L& G  a4 o# c; r0 B. e在 system_stm32f10x.c 文件里面, SystemInit()函数设置时钟。
3 n! V2 _6 X% m, v' G: K- p9 \9 n4 E. i# p/ {) W- X
  1. void SystemInit (void)& }3 f3 u: x  ?3 w5 K
  2. {
    & W  U0 `8 G- q
  3.     /* Reset the RCC clock configuration to the default reset state(for debug purpose) */% M. o9 o* E, ~+ `
  4.     /* Set HSION bit */
    $ t( F/ o% O3 ^. q2 [: r4 @* ^, q) R/ a
  5.     RCC->CR |= (uint32_t)0x00000001;
    ' X; O) ]3 F. s/ `5 X7 ^) S7 k* D
  6.     /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */* f7 }' y( D8 O* k. R
  7. #ifndef STM32F10X_CL
    , t6 t2 \5 _; {3 n1 m- a: @: o" M
  8.     RCC->CFGR &= (uint32_t)0xF8FF0000;% a$ j" W9 b6 h- W
  9. #else7 d$ p6 d: t: x
  10.     RCC->CFGR &= (uint32_t)0xF0FF0000;
    / i* f. x. H! ?7 R8 f' H4 G: z9 a
  11. #endif /* STM32F10X_CL */6 A9 M' ?5 e  [' K
  12.     /* Reset HSEON, CSSON and PLLON bits */4 c% x+ ?; S6 G5 \1 A9 F
  13.     RCC->CR &= (uint32_t)0xFEF6FFFF;6 y/ }" ~7 L! E" t
  14.     /* Reset HSEBYP bit */
    ' J, T8 |0 J# ~7 k
  15.     RCC->CR &= (uint32_t)0xFFFBFFFF;
    0 C! e! w8 T8 }) e0 l# U1 U
  16.     /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */* C1 L7 o% F+ m# g2 T
  17.     RCC->CFGR &= (uint32_t)0xFF80FFFF;
    % \8 P- n: f' ~
  18. #ifdef STM32F10X_CL
    * j1 s2 ?) ^8 H
  19.     /* Reset PLL2ON and PLL3ON bits */4 E+ G( L. F0 I9 m# q
  20.     RCC->CR &= (uint32_t)0xEBFFFFFF;5 ~8 ]$ I! @% b) B8 W* a* z  j3 Y
  21.     /* Disable all interrupts and clear pending bits  */( O5 I' T* _8 v. j6 M
  22.     RCC->CIR = 0x00FF0000;
    & A; o4 U7 N' R3 |' R7 F
  23.     /* Reset CFGR2 register */7 O. ]; h5 T% ?2 z+ R8 \% _1 s
  24.     RCC->CFGR2 = 0x00000000;
    / v1 ?( C3 N* y: u
  25. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
    2 p5 s6 A" k0 ]0 `+ e
  26.     /* Disable all interrupts and clear pending bits  */
    ) L. @* y, G2 a4 Z+ r# `
  27.     RCC->CIR = 0x009F0000;( w/ C* u0 ^' n0 ~" J
  28.     /* Reset CFGR2 register */
    2 R5 j# E& T! p- Z  o; d
  29.     RCC->CFGR2 = 0x00000000;
    / F& f/ }! S% ]- Z* Z$ N# S# [3 z  v
  30. #else
    2 B: q& w! |2 h9 b$ H  [  {
  31.     /* Disable all interrupts and clear pending bits  */
      F" d  r* m4 d% |, f
  32.     RCC->CIR = 0x009F0000;
    " C+ ~9 y* Q: H
  33. #endif /* STM32F10X_CL */; c4 \: I: p; o* l- ~
  34. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)3 X  Q6 w) f2 Z2 W  s0 J+ w' u- k
  35. #ifdef DATA_IN_ExtSRAM$ ]3 ^5 c( M0 u2 s2 S0 }2 I
  36.     SystemInit_ExtMemCtl();9 U  b2 ?# x. B% H* i, `4 {: }) Q
  37. #endif /* DATA_IN_ExtSRAM */+ b6 f3 J6 [* }
  38. #endif* j6 g- W8 d: Y4 I' D& _2 n9 o& i
  39.     /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
    3 h9 b. G2 K1 a2 T0 i/ u
  40.     /* Configure the Flash Latency cycles and enable prefetch buffer */9 w: d! k. }5 m8 v1 |- A
  41.     SetSysClock();' V; y! g) C) }6 w0 t
  42. 4 p( Z1 m! ~& u( G  p, w$ N
  43. #ifdef VECT_TAB_SRAM4 Z! c/ X$ R7 [$ |8 s9 A
  44.     SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */: g( Z2 V5 E4 [( \8 ~3 ^
  45. #else
    9 m3 j% o' |; W  |+ M& S8 V
  46.     SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */* G# q8 q* y/ x& e
  47. #endif/ p. S) D" i* r
  48. }
复制代码
8 p+ o8 Q5 {: V! Q4 s- o- Q5 h
如何要使用内部RC振荡器做时钟源的话,需要重写SystemInit()函数。设置代码如下:
  1.    /* 开启HSI 即内部晶振时钟 */5 Y7 @. v) v, J3 E4 @4 T
  2.         RCC->CR |= ( uint32_t ) 0x00000001;( H. Z+ }5 o  I
  3.         /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/6 r2 s( n' [# s+ h
  4.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;/ _& O5 h+ E! I+ W) p
  5.         /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/. S' h, ]; d/ _3 O& e4 I9 U) n6 [
  6.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                        //设置倍频后的频率! h# t( A2 u6 ^+ Q
  7.         /* PLL不分频输出 ?*/
    9 L; x5 z% h; H+ J* i; [4 X
  8.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
    4 {- M+ ~' _7 P" y" m: ?+ h; Z" l# Y/ n
  9.         /* 使能 PLL时钟 */# q( }1 M) n; E7 O" B* \
  10.         RCC->CR |= RCC_CR_PLLON;
    . h; s% K" u: Y. ^3 |
  11.         /* 等待PLL时钟就绪*/4 c; {% m; f0 y* r5 w
  12.         while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
    * C; N3 U  ]- k* [
  13.         {& W7 Z% ~2 ~* `; C
  14.         }
    4 [( u' A: X3 m+ k3 S1 F) z, Z
  15.         /* 选择PLL为系统时钟的时钟源 */" G  e# v9 o% n: _
  16.         RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
    ; l4 S/ o6 H  p( D0 R
  17.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
    : G8 T6 m+ f( n, \# F$ R% }6 S2 K
  18.         /* 等到PLL成为系统时钟的时钟源*/
    2 Z; G4 \2 ^, K* m
  19.         while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
    3 I/ M- x) C7 I" u, _% r3 J( k
  20.         { }
复制代码
9 v1 ]; k. h4 \  |! P9 U
为了方便和以前的代码兼容,这里使用条件编译来选择使用外部晶振或者内部RC震荡。代码流程如下:$ H1 o0 {/ k& ~; k
#if USE_HSI
  d  r; s' G, M+ `1 R/ H7 s/ o{undefined0 r% _( @) r: _5 |. m8 O; E  `; F
//使用内部RC
% c: c8 W3 o9 J9 R2 u}+ D/ F" a/ d0 w
else" ?  ?! T" ^0 c
{undefined
2 S2 v! q$ A4 [5 P//使用外部晶振4 e6 _, {7 o4 o& L5 r' p
}
- r$ c% h' t% `9 b6 A/ `0 a7 V- m#endif' ^( j+ V2 R% D' O# c
通过宏定义 USE_HSI 来选择时钟源,USE_HSI 为1时,使用内部RC做为时钟源,USE_HSI 为0时,使用外部晶振做为时钟源。
7 }" }7 P8 K# z9 e$ z修改后的代码如下:! b3 W9 r& \- F5 F
  1. * r; X: v+ s3 I
  2. #define  USE_HSI   0                        // 是否使用内部晶振  0 不使用  1使用% t; r# v; G. {% p, k
  3. void SystemInit ( void )
    2 D) m9 i5 G- f4 j, z' m
  4. {
    1 y. Y4 d# c) D5 [  ~4 u

  5. 3 l( ~1 W+ R" V% \3 l5 d! [+ R
  6. #if USE_HSI! V3 d7 p) B+ ~* F6 l. U( X; V4 h. a
  7.     {% l" W9 ^  H7 q" L
  8. //设置使用内部晶振) N& n! }) r' A+ D. A; L
  9.         /* 开启HSI 即内部晶振时钟 */) ~: ?$ W  ~9 q( J4 ~+ l, W
  10.         RCC->CR |= ( uint32_t ) 0x00000001;
    - g. ?6 E* j: @, A7 a
  11.         /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/+ c* F: [7 _9 Q* J/ I7 P/ B* ~- }2 e
  12.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;. m+ C' R+ Y9 e( v. A. @* X
  13.         /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/6 q  A  x1 k7 p
  14.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                         //设置倍频后的频率
    8 L5 |/ f9 z( ]! M  D
  15.         /* PLL不分频输出 ?*/& Y* @; y/ m3 J3 V" }' U
  16.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
    / N6 F- w/ b! |. _
  17.         /* 使能 PLL时钟 */( a' w  p" e) R3 Z8 \  b% j
  18.         RCC->CR |= RCC_CR_PLLON;
    % ?8 i  A7 f. M' I
  19.         /* 等待PLL时钟就绪*/; L6 T1 W5 y. N
  20.         while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )( I* e) a3 y" S1 s6 K: Z
  21.         {4 i# @% @! ]) N, O" w) S, q+ ]7 j% Q- V
  22.         }1 V9 o/ {# C( ^. D6 l
  23.         /* 选择PLL为系统时钟的时钟源 */
    5 v. m, x' p- F! F5 c" u) G
  24.         RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
    : u4 E5 t, p: h' K$ r
  25.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
    5 n5 @8 ?3 F( F& ^% c& [
  26.         /* 等到PLL成为系统时钟的时钟源*/
    % k6 Q9 @, u& f' u& }
  27.         while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
    6 K- Q- e; y6 Z( k, D
  28.         { }1 z+ x, S/ M: r: E1 }6 J9 `
  29.     }0 [/ b3 N9 q3 J# v0 S) i+ O3 f
  30. #else
    ) ~9 o2 e) y$ }$ C
  31.     {
    % R, r1 d/ ]9 M( z: _. S
  32. //设置使用外部8M晶振1 r' P# u0 u, b' c- [: m
  33.         /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
    0 Z3 E! @  j9 T1 z- o* g1 ]$ {
  34.         /* Set HSION bit */1 m+ g+ E3 F0 T$ g% T9 z
  35.         RCC->CR |= ( uint32_t ) 0x00000001;' m2 h5 o' C8 B$ Y% |! e

  36. - U2 x: s8 L6 ]$ `3 c( z" b; x1 b
  37.         /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    7 [; [3 M  J+ C" P( G% m
  38. #ifndef STM32F10X_CL8 Y: J! v  O# Z# T& e4 a& M: V- x
  39.         RCC->CFGR &= ( uint32_t ) 0xF8FF0000;( E; _+ x, \* P$ m; R) q1 `6 a
  40. #else
    ' K$ H( x; C- `7 U
  41.         RCC->CFGR &= ( uint32_t ) 0xF0FF0000;, z2 P' \9 x# ^( }- y8 H
  42. #endif /* STM32F10X_CL */) N9 f) _# r# m6 y
  43. & K. ^) v2 d7 x, A2 s
  44.         /* Reset HSEON, CSSON and PLLON bits */8 u9 H4 G4 Y( [
  45.         RCC->CR &= ( uint32_t ) 0xFEF6FFFF;6 R5 L! p6 v1 s+ F

  46.   o5 K7 ^, D0 B+ A+ z- O' U$ ]9 [" n' O
  47.         /* Reset HSEBYP bit */: \2 k: M& r; c' o. L
  48.         RCC->CR &= ( uint32_t ) 0xFFFBFFFF;9 X9 t5 i, E3 ]) v

  49. 7 N0 E0 d) F: I0 c; }
  50.         /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
    3 q7 z2 |5 d5 H% s8 C7 ?) j
  51.         RCC->CFGR &= ( uint32_t ) 0xFF80FFFF;
      ?* V: ~0 {& M7 ]# _
  52. : c  M( Q. T* J/ q: u4 r
  53. #ifdef STM32F10X_CL5 ~$ X; w: Y; r% e2 O! v7 {$ m
  54.         /* Reset PLL2ON and PLL3ON bits */3 ]) B9 ]7 h4 a: x1 z
  55.         RCC->CR &= ( uint32_t ) 0xEBFFFFFF;
    " T% x$ {/ P/ |- @! c, ~/ t1 V, D

  56. - e4 Z  w$ H+ N* i' q7 F
  57.         /* Disable all interrupts and clear pending bits  */& t9 j( }& D# T; t' M3 b
  58.         RCC->CIR = 0x00FF0000;
    & d3 n1 O2 z) Y/ g/ x
  59. 8 l" M9 c( ]$ v% b
  60.         /* Reset CFGR2 register */
    ; ~4 W6 _. g- W0 Z/ c
  61.         RCC->CFGR2 = 0x00000000;# t# W7 `  H1 U# D% P
  62. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
    0 j# A! v2 L- F! [- U) ^5 W
  63.         /* Disable all interrupts and clear pending bits  */! t3 Y$ o$ ?; f3 q- `6 ?
  64.         RCC->CIR = 0x009F0000;
      `4 o) X" i7 ]$ ~! o/ A

  65. 6 u4 ^% v! {% [5 u  I& C/ _% t: V. c
  66.         /* Reset CFGR2 register */
      Q  x2 [2 }- D8 B- O* J# r
  67.         RCC->CFGR2 = 0x00000000;
    8 l) ?  t% _/ Z- f3 J. t) p
  68. #else
    7 e" ~: d; J7 m; P
  69.         /* Disable all interrupts and clear pending bits  */# ?8 H6 ^! P! R% F! M
  70.         RCC->CIR = 0x009F0000;
    : o+ _& k9 h1 ?
  71. #endif /* STM32F10X_CL */
    & x8 u$ K! W1 k/ z" t& Z+ P
  72. + K. {7 H! B! C9 A
  73. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)! |( r' q4 e2 a* W
  74. #ifdef DATA_IN_ExtSRAM" c: I$ t$ [$ \$ j
  75.         SystemInit_ExtMemCtl();
    3 A& t! Y9 N/ Q" ^3 s
  76. #endif /* DATA_IN_ExtSRAM */  S! T% q; ?& i. S0 M0 w+ G
  77. #endif% F  x7 D1 J* s& S; M+ z- Y
  78.   h# I5 `" f) _# J4 |! ^; c
  79.         /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
    2 h0 @8 h$ G1 ^) Q9 o' P9 Z& a
  80.         /* Configure the Flash Latency cycles and enable prefetch buffer */* B* ]" l# S/ `* F. i
  81.         SetSysClock();
    2 r+ o$ f& q( t. t& S& C9 [
  82. $ A5 l/ x6 i* W/ l% t
  83. #ifdef VECT_TAB_SRAM
    % h6 O5 y' J3 `6 `  f
  84.         SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    # w! U! {" C2 ^% l$ c& ~" H; V4 ]
  85. #else
    ) ~( v2 ?( {0 w. w
  86.         SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
      B0 w. \, W1 \2 C) Z
  87. #endif
    4 u% W$ y# J3 h( i
  88.     }
    ( _" V  f% Z; b* B( d
  89. & R3 q9 t) T3 h4 h8 Y9 v
  90. #endif1 |' [1 H6 M9 d3 Q& L
  91. }
复制代码

& M$ N0 G8 c( p) `+ i* Q' ~9 i9 n内部RC默认为8M,将倍频数设置为9,这样使用内部RC振荡器之后,时钟频率就是36MHz。为使用外部晶振频率72MHz的一半。
; P: }" `4 ^6 m" I* a5 }
. s. I- k: N- x5 J. x! a
  1.   /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/1 s3 H" E" _" J
  2.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                         //设置倍频后的频率
复制代码
& V$ q' B2 E) J+ L# U: t
这时候在运行代码,用示波器测试LED的电平,发现是高电平200ms,低电平200ms。比使用外部时钟慢了一半,说明使用内部RC振荡器的设置代码是正确的。
" ~, x. B6 D; G" D+ M4 f& V- S( b1 O$ v5 Q: N
0 I! D2 H  w/ n, l  g& ^
收藏 评论0 发布时间:2022-3-22 13:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版