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

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

[复制链接]
STMCU小助手 发布时间:2022-3-22 13:00
平时在做项目的时候都用的是外部晶振做为时钟源,想试试用内部RC振荡器做为时钟源,在网上搜了一下如何设置内部时钟,发现资料比较少的。决定将设置内部RC振荡器做为时钟源的方法记录下来。
4 I$ R/ X6 h9 K用的单片机是STM32F103C8T6,项目工程是在正点原子的示例代码上修改来的。用一个LED工程测试,在主程序中闪烁LED灯。
" i$ f2 |  \" n  s: ^$ q6 \6 ^) u9 C3 }5 e8 O# }
  1. #include "sys.h"4 R; s) G9 u. E" `# R8 K/ O
  2. #include "delay.h"/ {. O  M! ]9 Q" T  D  @" U* Q
  3. #include "usart.h"+ X5 p. `) B! G+ G
  4. #include "led.h"+ F' P% n3 U8 G( L# g% _
  5. int main ( void )2 s( n2 f% b" X" ]( a3 f& P5 E
  6. {
    - R7 a+ J' `" @& z1 |
  7.     delay_init();       //延时函数初始化
    : [, H' u! o7 U: V2 y( h
  8.     LED_Init();         //初始化与LED连接的硬件接口0 V5 a% R' U9 V0 S6 r& M0 h( f
  9.     while ( 1 )
    * u/ y0 h/ B& E" m: C
  10.     {
    8 Q5 u' Z- k# F. F1 m
  11.         LED = 0;
    + F6 P9 d4 @! m  W; z3 G4 j
  12.         delay_ms ( 100 ); //延时300ms
    * V* \; ^& X2 s( l% ]- ~) S+ a
  13.         LED = 1;$ f( X3 y6 r+ Z
  14.         delay_ms ( 100 ); //延时300ms; O7 Q1 L% |4 g' H
  15.     }
    . B9 h6 b- z4 G6 C  |
  16. }
复制代码
& 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
  1. void SystemInit (void)8 b, {) r. t, t6 N
  2. {  W, ~$ r$ z5 D1 q- Y- C1 X
  3.     /* Reset the RCC clock configuration to the default reset state(for debug purpose) */6 T4 p3 N$ A: r& S1 K7 s8 ]
  4.     /* Set HSION bit */9 z7 k0 ?* N) C- c* d; l, |
  5.     RCC->CR |= (uint32_t)0x00000001;
    & G! Q% `, ^# W) f# l; O- k
  6.     /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    " L* o" l* k: L, N+ L
  7. #ifndef STM32F10X_CL
    / j1 w. {8 m/ K2 }2 x1 }  _9 R
  8.     RCC->CFGR &= (uint32_t)0xF8FF0000;! u$ U3 I0 z1 r! B7 U
  9. #else% f$ E1 W3 _& I
  10.     RCC->CFGR &= (uint32_t)0xF0FF0000;1 t0 J" |, ^4 @+ [  D
  11. #endif /* STM32F10X_CL */
    7 Z* O- e! ?! Q9 ~9 p- o
  12.     /* Reset HSEON, CSSON and PLLON bits */4 e/ S" z; v& n5 H( w
  13.     RCC->CR &= (uint32_t)0xFEF6FFFF;
      m; I4 E4 ?) z% c$ v4 o
  14.     /* Reset HSEBYP bit */
    9 B7 D$ O3 I$ C2 W9 K3 \. b3 w9 S3 T
  15.     RCC->CR &= (uint32_t)0xFFFBFFFF;
    ) ?/ `9 e7 W+ Z0 @; L: C
  16.     /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */8 ?% N, y/ Z1 u1 j+ \( z
  17.     RCC->CFGR &= (uint32_t)0xFF80FFFF;' @/ ?- d; @" |+ X
  18. #ifdef STM32F10X_CL
    9 s* x; g- Y$ m  J
  19.     /* Reset PLL2ON and PLL3ON bits */& y# g2 n7 |# U8 `
  20.     RCC->CR &= (uint32_t)0xEBFFFFFF;
    # j! ^- c, |) I7 X# L) G' A
  21.     /* Disable all interrupts and clear pending bits  */
    * a7 z+ K& i8 Q8 g
  22.     RCC->CIR = 0x00FF0000;. X; e0 B# x7 p3 ]" D5 Q$ g
  23.     /* Reset CFGR2 register */
    " S& d8 M  I0 L; a& u6 y
  24.     RCC->CFGR2 = 0x00000000;- Y$ G! H* ]: W, ~, O7 u
  25. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL). Q3 M( l. ?+ Q
  26.     /* Disable all interrupts and clear pending bits  */  p% j2 F& b/ C* c* X; C. G7 ~, B+ ^
  27.     RCC->CIR = 0x009F0000;$ L* N2 k' z, O, ?
  28.     /* Reset CFGR2 register */
    4 N3 A+ ?. Y" E; L
  29.     RCC->CFGR2 = 0x00000000;
    3 S0 [2 ^1 i+ N6 {# w
  30. #else
    / H: y. S! ?# D7 U* R
  31.     /* Disable all interrupts and clear pending bits  */
    5 I) R; i. t- B- e
  32.     RCC->CIR = 0x009F0000;+ [9 v6 m3 X3 W( }/ A/ ?- G0 c
  33. #endif /* STM32F10X_CL */
    4 ?$ b) C6 o: u& ^9 R8 n
  34. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)& d: t+ }4 K# @1 k$ R3 i# O; Y
  35. #ifdef DATA_IN_ExtSRAM. }# U1 X/ \% q+ [9 ^  l
  36.     SystemInit_ExtMemCtl();6 b& ?/ Y& d6 \( C9 M5 f8 d
  37. #endif /* DATA_IN_ExtSRAM */
    % m; t; Q2 a% L+ O5 c/ A
  38. #endif
    $ D& ?" @! f# x4 ?' Q& I
  39.     /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */1 L4 `$ T) I) Y: d
  40.     /* Configure the Flash Latency cycles and enable prefetch buffer */( ?" W, W2 J# M7 y+ {
  41.     SetSysClock();# Y9 i  J$ T2 L3 l/ r& T2 K
  42. ! B8 L5 v) ^; o, h% V+ Y/ b
  43. #ifdef VECT_TAB_SRAM  }" C! g) n& \. q8 l3 `# f
  44.     SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */9 ^8 R  Q/ `( M0 \
  45. #else# E5 E8 l+ [8 A2 l- k2 \
  46.     SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */3 S5 ^) c- {0 B, B% u/ A
  47. #endif
    7 C* j4 u6 a' j0 ^
  48. }
复制代码

" ^' V3 u( w  w. w2 e如何要使用内部RC振荡器做时钟源的话,需要重写SystemInit()函数。设置代码如下:
  1.    /* 开启HSI 即内部晶振时钟 */
      P' Z1 N6 ?2 ~. S5 b, d( X, X
  2.         RCC->CR |= ( uint32_t ) 0x00000001;! o9 P7 m6 ?$ I* o
  3.         /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/. ]: X- U/ q. x( u5 G7 G
  4.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;$ D! [- S0 s$ q+ Y
  5.         /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/, O9 d" |/ F6 c1 J/ Q
  6.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                        //设置倍频后的频率2 e$ y$ G, {3 r# G
  7.         /* PLL不分频输出 ?*/( i; z! |1 |0 B6 Q% A* _: f
  8.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
    : `3 o. _/ ~0 E; J
  9.         /* 使能 PLL时钟 */
    & q/ d6 L4 B0 H6 I9 f9 t% d
  10.         RCC->CR |= RCC_CR_PLLON;. q1 t# n, I( `- G) u  T4 M* }, A
  11.         /* 等待PLL时钟就绪*/
    ) D( w3 s( p; t* g8 P! _
  12.         while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
    6 k- r: T6 d+ D; `' z4 W
  13.         {
    7 u! K- j4 u/ I) S6 A; b8 D! e, N
  14.         }, p, G! l+ T! z0 r
  15.         /* 选择PLL为系统时钟的时钟源 *// o" ?' t; h/ N
  16.         RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
    + q/ a) C* F" D$ x9 f
  17.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;+ A' q6 s' h1 T; G1 \
  18.         /* 等到PLL成为系统时钟的时钟源*/& M- K% ?0 A* B3 R/ T
  19.         while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 ): ~* z1 a9 s& u
  20.         { }
复制代码

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
  1. 4 `( P9 L; T, d, Z2 o3 a8 _
  2. #define  USE_HSI   0                        // 是否使用内部晶振  0 不使用  1使用' v6 [7 L! U1 o% w6 O# P1 A
  3. void SystemInit ( void )
    * @# t* d1 ~1 L% ~9 R
  4. {
      c# [8 ~5 c. h  m2 X0 P* O! @

  5. 7 ?9 W" w6 b/ O) R) U5 ?
  6. #if USE_HSI
    # m4 Z3 M4 L2 Z' @7 U, p/ g3 a
  7.     {9 g3 f# K, X" I0 I
  8. //设置使用内部晶振1 V# o' i- P7 p# m- U: L
  9.         /* 开启HSI 即内部晶振时钟 */7 B, g# X& R" X
  10.         RCC->CR |= ( uint32_t ) 0x00000001;
    # Q: V9 L2 }+ i6 |+ _6 |9 H
  11.         /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
    ' b1 Z* S6 s) p, F) m0 q
  12.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
    ( x0 ^- h! M. y- D8 r
  13.         /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/' |% _5 K$ D4 j9 `6 F/ _
  14.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                         //设置倍频后的频率
    7 a# ]# H- ~% W/ _# E
  15.         /* PLL不分频输出 ?*/+ C5 ]4 r2 b( d" z' ]/ u. q
  16.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;; }# S- T  A" N& a( W
  17.         /* 使能 PLL时钟 */
    8 N5 ?5 l. U2 u2 p7 X
  18.         RCC->CR |= RCC_CR_PLLON;- P$ K/ p, W. X( k3 @8 x
  19.         /* 等待PLL时钟就绪*/6 c' [5 _% R$ w! O
  20.         while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
    * a% q" U1 h% p. X9 P, J% o
  21.         {9 P. r# S9 B* [  y7 b: I" }0 q
  22.         }
    8 A. K/ x' y4 @
  23.         /* 选择PLL为系统时钟的时钟源 */& c3 L7 d/ d. L( L2 n
  24.         RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
    ! p0 o  I. Q2 L  I- z: C8 A  A7 [' C
  25.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
    ' P) Q) v" D4 u# T1 P% u" A( i8 Z' u1 b: T
  26.         /* 等到PLL成为系统时钟的时钟源*/
    , b* B; o; K  i3 z4 p7 b5 ~- Z- D
  27.         while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )4 a, i( X1 X7 w. x9 ?1 {: m
  28.         { }3 b+ @" l) D5 p/ z5 n
  29.     }: g5 H, Q* |7 ?) s# I) r" A2 [
  30. #else
    . f, L: r1 V  `' d" _6 p
  31.     {
    9 [5 o$ q9 Q" q; r2 I
  32. //设置使用外部8M晶振7 U7 }; o& B- h' X! a; _# u) x
  33.         /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
    5 w" q. B+ f: |3 n9 [- w3 m3 r
  34.         /* Set HSION bit */
    ; H0 S6 V6 a% F) o7 N% J
  35.         RCC->CR |= ( uint32_t ) 0x00000001;
    ( {0 ]- ~0 Y6 F4 b: u& ~$ v5 Z
  36. * H' W1 `8 l3 F- P$ A; J1 c
  37.         /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    4 H  }" Q0 i+ R0 Z& P5 L
  38. #ifndef STM32F10X_CL7 i, j2 ?- g9 {& g% A3 \# B* n
  39.         RCC->CFGR &= ( uint32_t ) 0xF8FF0000;  @0 u1 F( d5 G) k# B
  40. #else
    - w/ _- x$ }# s. [2 W
  41.         RCC->CFGR &= ( uint32_t ) 0xF0FF0000;* z$ A. {5 `/ K& K6 c8 v
  42. #endif /* STM32F10X_CL */
    ; T# H2 Y. I# _: F; ~
  43. 3 }+ }( Z) \* C& G
  44.         /* Reset HSEON, CSSON and PLLON bits */
    . K& v4 p1 v! P/ l
  45.         RCC->CR &= ( uint32_t ) 0xFEF6FFFF;' `7 `0 C4 a5 I! I. P

  46. ) p$ s2 W4 z6 t! b5 N
  47.         /* Reset HSEBYP bit */: z: ?7 C6 Y. e3 A& @3 j0 E. t
  48.         RCC->CR &= ( uint32_t ) 0xFFFBFFFF;
    7 \3 ]0 e( I  ]& L! _8 S

  49. 6 F5 F: N& b  I( [& j3 x
  50.         /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
    * c( G" }, Z1 F! d5 L4 Q
  51.         RCC->CFGR &= ( uint32_t ) 0xFF80FFFF;# h1 U1 N: U- ^, ~) M

  52. 9 }$ z, ~, {* ^# K! ]$ a! h; v
  53. #ifdef STM32F10X_CL" Q. }# B! ~& o: R9 \+ H
  54.         /* Reset PLL2ON and PLL3ON bits */3 N+ _! O" D+ |  w
  55.         RCC->CR &= ( uint32_t ) 0xEBFFFFFF;
    ) W9 S2 f% Y$ l" b5 |0 C
  56. 0 |! T0 R# D7 G. P' r
  57.         /* Disable all interrupts and clear pending bits  */, u' g' C8 O5 f' e+ }+ z
  58.         RCC->CIR = 0x00FF0000;8 D$ S4 X) i/ c( A8 ?) s, `

  59. , R3 H" {- a4 q/ N
  60.         /* Reset CFGR2 register */
    ! @. B* U& c& @6 T5 v
  61.         RCC->CFGR2 = 0x00000000;
    " r( _9 Q/ p* v6 g; N0 ~6 v
  62. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
    8 w$ y' f" J: s8 w& y
  63.         /* Disable all interrupts and clear pending bits  */5 V9 \' p% Z+ W
  64.         RCC->CIR = 0x009F0000;
    5 ^- T/ Y" w# J9 i2 j
  65. . Z+ C3 `" e" C) J; W& o- }! f: l. ]
  66.         /* Reset CFGR2 register */6 w$ `; m, Q; w
  67.         RCC->CFGR2 = 0x00000000;
    . [* q0 q; X( q) U( B$ \9 b% C
  68. #else: n$ K* ?% T$ d1 `
  69.         /* Disable all interrupts and clear pending bits  */9 Z; i/ r6 z9 K2 A6 G8 ]' _0 g. [
  70.         RCC->CIR = 0x009F0000;
      Z6 q3 f% T7 h: r- ~/ G
  71. #endif /* STM32F10X_CL */! A: r$ f: y# l* j  B# q3 o9 c

  72. . R$ v3 A! _: K. A
  73. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)8 k1 ~+ ]/ `8 Q8 U% M. ]
  74. #ifdef DATA_IN_ExtSRAM
    4 i: f: t2 w3 O/ g6 ~; N# w
  75.         SystemInit_ExtMemCtl();
    9 T* z, F. u# E
  76. #endif /* DATA_IN_ExtSRAM */
      H4 C( {7 B  S2 g. n9 \: B
  77. #endif
    7 V, ]) R. q- x- @- z

  78. # t0 [2 p/ X3 B2 O$ }) w
  79.         /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
    " E1 ?4 Z2 B2 L9 D# h
  80.         /* Configure the Flash Latency cycles and enable prefetch buffer */
    ' W! G+ h  h1 h5 b
  81.         SetSysClock();
    9 z5 Q: p2 w$ }
  82. % i  g3 V' u3 l6 D) ^' h
  83. #ifdef VECT_TAB_SRAM3 R7 L6 N3 R# N, J
  84.         SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    + |9 J4 T) n; h% a" S+ \# y
  85. #else
    $ W' Q+ [) {7 c7 @6 M* V
  86.         SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */& l. T8 I# l) o% W# v
  87. #endif
    0 E3 \  c9 c# q; h  A
  88.     }5 H% K" C$ A/ z2 P  |
  89. 3 a6 F( v: l5 k! h( ]7 b2 [
  90. #endif
      S3 f% O: |. C8 n5 s
  91. }
复制代码

, 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
  1.   /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/* U8 T/ a( U( [: P
  2.         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
赞 收藏 评论0 发布时间:2022-3-22 13:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版