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

STM32库开发实战指南F103 -- 3、RCC-使用HSE/HSI配置时钟

[复制链接]
TLLED 发布时间:2018-12-8 14:43
本帖最后由 TLLED 于 2018-12-8 14:42 编辑 3 i% g8 O. Y2 d; |! H; ]

  M$ g# o; `0 ~/ h* z8 s/ X    通过第16章节 -- RCC-使用HSE/HSI配置时钟  的学习来重新认识系统总线和外设时钟的配置。 4 b" l$ o. h; T: Y- G/ B

* S" u* L: T- ?9 K; f* M    一、手册中有关时钟配置的内容
' K! ~; R! M- R" R) b# U- M5 J6 X3 `, A1 ~& |

1 N4 Q& }7 Z0 F4 x4 ?" e. [# o! ?. N    1.1、系统时钟框图: 9 [7 t( m3 h7 _) Q1 C9 b
         里面显示出STM32芯片所有时钟和有关配置的寄存器位              1.png : n. X9 ^. B0 \; l

: {' U2 N" u8 \1 E4 i2 I8 E( W    " F/ s% k: V0 D3 I( u. k- z- Q* @
    二、系统启动有关时钟配置代码

  n% h6 ]' L8 N, s( s3 L4 w5 W$ G2 i; R: g  p: v
    2.1、系统启动分析* y3 D% K( S" @5 A7 v
        上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
7 d  \% T) z) s, m* X: F7 L  P         100.png 5 y! L0 {& I" A& l3 Y2 k
         里面有执行SystemInit系统初始化程序
) C0 Z5 c3 M9 n" J        
101.png & t1 `* u, L3 O% Y) c" d
         102.png 0 `2 \, G6 K  l- u) C: @, {* p
         103.png
       里面调用SetSysClock函数设置系统时钟
3 x" ~0 D( Y1 ?9 s       104.png       
/ f( M# V% d' \0 Z       SetSysClock函数配置为72MHz后调用SetSysClockTo72函数) c( _5 K* c8 e2 u2 S8 e' u
       105.png
# F1 K8 A* Z" I+ E8 @9 R, Q       106.png
" M% r4 [: B: b. E- C       107.png

2 c' ~' Q+ Y& S, L$ ?$ j/ S       108.png
5 Q! O6 ]9 Q6 N# V) `: L        上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。

; D2 `; i- u; X2 t* L    ) K4 _0 i, X) m
    三、时钟配置实例
+ F  p, C: a+ U8 a& s: g
6 E  m5 b; m. w6 M8 F
) N1 F, N$ ~' A
    3.1、配置HSE时钟  
# s7 S0 p/ {" ~6 F        了解系统时钟配置流程后,来实践使用时钟配置。
5 S# ^3 ^2 k, V' }4 }        在系统时钟框图中,HSE时钟配置
* Z, h" |% M& m7 A         109.png 8 t* c. {# `/ F$ h
    >选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振
5 q1 x# D6 R# ?$ J' }    >通过PLLXTPRE来选择HSE时钟不分频还是2分频。
  q1 s% o- Z4 w% Y    >通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。. `! e8 V( \) M# Y
    >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz
) S4 R# \9 U  P
    >通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。
( v, s" v0 G5 S" t6 ]+ \% n% \* P
' M- k8 {. e( F6 S! x

4 C, }% _1 z4 C2 K    3.2、程序源码# N; [# g4 `. Y" |! h) [7 `( S
         3.2.1、HSE时钟初始化' L+ d  m9 [/ x/ Y8 o' ?" C
         PLL时钟倍频到72MHz) |1 ^& f# B& V' B
   
  1. static void HSE_SetSysClock(void)2 H8 f% [% _1 T/ p
  2. {2 J, I9 ~) w, x/ Y; r& w, E% P
  3.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    ! z' t5 i2 s' J" C# B
  4.   ! }; J- g7 R/ I2 g) C. D
  5.   RCC_DeInit();                                                                                        //RCC恢复默认状态  
    4 k$ d) U3 ~- y; G
  6.         RCC_HSEConfig(RCC_HSE_ON);                                //打开HSE时钟
    % o3 _" r" D0 g7 G0 ]0 C7 }* m
  7.         6 p6 U2 P6 M0 q$ u3 _; P9 k
  8.         HSEStatus=RCC_WaitForHSEStartUp();   //等待HSE时钟稳定
    ) M7 J# E. g! C0 }; q/ ~. B1 F/ r: W
  9. 6 U& L5 i/ B% n4 ^' q
  10.   if (HSEStatus == SUCCESS)8 ~3 }" m* O0 u+ J
  11.   {
    * G0 `# z* L  i9 y7 ], O
  12.     /* Enable Prefetch Buffer */( T* [( {) u2 V
  13.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);            //使能FLASH预存取缓冲区
    . E' l) r0 O. R3 |
  14.                 FLASH_SetLatency(FLASH_Latency_2);                                                                                                7 k2 Y" W/ U/ |! B, i

  15. , o: K1 Y7 ^5 V/ e; [$ y
  16.                 RCC_HCLKConfig(RCC_SYSCLK_Div1);                                                                                                        //AHB - HCLK=SYSCLK) ]( l7 k( p) B4 O
  17.                 RCC_PCLK1Config(RCC_HCLK_Div2);                                                                                                                //APB1 -- PCLK1=HCLK/2  m& f& f+ i8 l5 R9 C
  18.                 RCC_PCLK2Config(RCC_HCLK_Div1);                                                                                                                //APB2 -- PCLK2=HCLK/ k# `; R4 @& h5 b  s; J2 O

  19. " D$ m: d. k* M% m& \
  20.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                        //PLL倍频
    0 q3 c) o2 z6 d, ^3 A. r9 r% H
  21.                 RCC_PLLCmd(ENABLE);                                                                                                                                                                //使能PLL
    5 w0 W% Z2 f8 J+ Y6 ?& @  ?: _
  22.                         - z+ ]' a' \' `, |( w
  23.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)                                        //等待PLL稳定% H5 W) l) a8 D" r
  24.                 {0 s- @# W/ O- w
  25.                 }
    / O  {" B8 K6 S  M7 y, S( S9 V
  26.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                                                //PLL稳定后,时钟切换到SYSCLK# B: t9 M; `8 m, g
  27.                
    4 A( K& D( x& n+ ]- I
  28.                
    ' Y, l: ~' E! f* Y# ?* L5 X& d
  29.                 while(RCC_GetSYSCLKSource()!=0x08)                                                                                                //读取时钟切换状态位,确保PLLCLK被选为系统时钟, R9 ?* A; N) t4 d! u
  30.                 {
    . O4 ]' o7 N' D1 v) O# v& i
  31.                 }! y. b  t2 h0 Y1 Z3 n5 m+ \8 ~; \
  32.   }
    " h& N! Z& i" v6 K7 t" A3 P% L+ E
  33.   else  W3 p  X8 y2 O: D5 \
  34.   {
    8 o% v7 z' {8 K
  35.   }- J- V$ g! @( }
  36. }
复制代码
       3.2.2、MCO引脚初始化
7 r) D1 U8 O8 G5 d: `
  1. //MCO引脚配置
      y* T  A2 c3 _2 ?* Y( v& }
  2. void MCO_GPIO_Config(void)6 Y! y- \0 |- v% {
  3. {. q8 S  G8 E2 z! t4 K
  4.         GPIO_InitTypeDef  GPIO_InitStructure;7 _, j3 a" r. {
  5.        
    9 p% y! l5 l: \! W( Q8 t+ c9 h9 r
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);                 //使能PA端口时钟' }! V& n7 B; k, q; L' q
  7.        
    - u$ m( L  ~8 ?+ L: Z- y( [
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;                                                                 1 I& q" c7 G7 W  A- z( R. ^0 P
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                          . A. W8 }- u* b$ V. a: e
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //IO口速度为50MHz6 J* e: [: x. z) z
  11.         GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                
    . d3 {% m9 q) H2 I, L2 i& Y) w$ j
  12. }
复制代码
       3.2.3、LED引脚初始化
" R. S" t% a6 U$ b9 `$ C
  1. ( x2 w) q6 @9 V' H0 E% e
  2. void LED_GPIO_Config(void)2 \$ c! B( ]- Z' R/ Q! z1 ]6 H
  3. {
    5 m& U& Y* y1 v" J
  4.         GPIO_InitTypeDef  GPIO_InitStructure;# }! I: k& z2 Q% E
  5.        
    ' |3 V& z# t. x& e& t# d: K
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);                 //使能PA端口时钟
    ' o4 a7 v, k' u
  7.        
    ; g! {* q% D  Y# l: l$ n) A
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                                                                
    8 n: i* a0 t# }- T4 M6 G
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                          * o$ M9 ?# u$ |6 c) ^8 U1 ?. L
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //IO口速度为50MHz
      B: \0 W* y5 @
  11.         GPIO_Init(GPIOB, &GPIO_InitStructure);          w3 [1 N/ l% ?& ^  O' G) n6 {0 o. J$ d
  12. }
复制代码
       3.2.4、主程序
" |0 @3 V+ i4 r/ F
  1. int main(void)
    , k0 ?# c5 r. ~+ Y4 [/ V. p5 c/ H
  2. {5 K" z0 g9 ]# G) F2 ^* A! c
  3.         uint32_t i;5 A# E0 @, K& g6 H' ?& D/ L8 w/ k
  4.         HSE_SetSysClock();4 w. U& O3 S+ [
  5.         MCO_GPIO_Config();
    % V" p4 R3 G& b* X  f* c3 i
  6.         RCC_MCOConfig(RCC_MCO_SYSCLK);        . }. W* _& B% _* R3 q1 k2 E
  7.         LED_GPIO_Config();       
    4 K2 S; h7 p% g" I
  8.   while (1)5 z* P3 z; I0 C
  9.   {
    , x- @# \& w# v+ i
  10.                
    $ n4 G; \- e; D* D
  11.                 for(i=0;i<0xffff;i++);, V9 H( |8 k% l9 ~' v( r
  12.                 GPIO_SetBits(GPIOB,  GPIO_Pin_9);
    : e/ a) [1 h% E2 r
  13.                 for(i=0;i<0xffff;i++);
    7 s4 c/ ~. R9 M% H
  14.                 GPIO_ResetBits(GPIOB, GPIO_Pin_9);6 x3 k! ~3 |7 o* q% j  C
  15.   }
    ! e* `. G9 P( V. D1 ?) ]( c
  16. }
复制代码

+ O  X' ^4 o  b, u' \' I6 I    四、程序执行结果
, g! W# h6 l, z9 Q# l* c7 R; F6 \! b6 v1 }" V
- y# R6 s* p  g7 F/ c
    4.1、PLL时钟设置为72MHz,倍频系数设置为9( Y$ K/ e  h( B& X, O
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                        //PLL倍频
: M4 ^9 e/ g4 a9 ?; z        4.1.1、MCO输出时钟频率72M7 C. `9 ]2 E' A- U! N7 F# O
        
F0002TEK.png
+ V1 P: L, x% |2 X  @% s2 O        4.1.2、LED引脚输出

* v! P' e; E  ]         F0003TEK.png " U; g; |: d, ~. w: R* [

# U- S& A! B. j3 T  R   
4.2、PLL时钟设置为56MHz,倍频系数设置为7        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);                        //PLL倍频
# m6 Y& ~" n. w4 B+ x) c; k        4.2.1、MCO输出时钟频率56M
! Q/ `+ ~3 b* N2 K5 W- m  j3 W3 K" [         F0005TEK.png
# U  |# u* r7 ~        4.2.2、LED引脚输出
- g! }6 F+ y; t- C, [5 q( m) f  m        
F0004TEK.png
9 U; A9 d% I1 r        LED输出宽度比72M时钟时,宽度变宽3 g  A# f; o0 [6 v; S. W' ?
    4.3、PLL时钟设置为88MHz,倍频系数设置为11        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11);                        //PLL倍频
) }* v% Z7 N( G% e# r  J: v" p% u        4.3.1、MCO输出时钟频率88M
# i" l- F% o* W  l7 ~" t# C         F0006TEK.png 2 }* @! L0 M) ?
        4.3.2、LED引脚输出
! ^! w3 H" i* X        
F0007TEK.png 5 {' u! T! l( U
        LED输出宽度比72M时钟时,宽度变窄

! v9 D. ^! c& P9 v( A* O9 ^$ y6 n* t- S1 K
    五、结论

( a' x  i0 e% {  X# {3 b8 h6 ]5 r9 Q& r9 O% {
0 L1 D. i2 K7 n5 u# S
         使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。0 G, w- K4 k$ G# b, l2 D
5 P& Q- g( o% w& ~  I+ }6 D# W
1 B( S0 b4 X+ ]# h* g, k" b
: u/ q7 [' T; p

$ M1 Y; U( l1 P

) P6 t* ^3 P& o1 c: }! B5 i6 N9 R& k7 ?  L9 @8 p' S- F2 Q
$ D- t% Z. S- `$ ~% F9 f

& g, A4 z2 `- Y& u8 h; S

评分

参与人数 1 ST金币 +20 收起 理由
STMCU + 20

查看全部评分

收藏 评论4 发布时间:2018-12-8 14:43

举报

4个回答
STMCU-管管 回答时间:2018-12-10 10:15:27
支持
hhhhhhhaa 回答时间:2020-4-29 15:05:17
您的配置里有这样一句
& }: E4 K+ I3 J4 l4 tRCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));% x* V, `3 S1 ]+ n0 G1 S1 v, j$ H
这句话是把第16-21位清零
hhhhhhhaa 回答时间:2020-4-29 15:06:54
PLLSRC:PLL输入时钟源 (PLL entry clock source)  位168 ?) f# O& ?1 a0 G
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。
: |! m3 r5 m6 _! X; ?0:HSI振荡器时钟经2分频后作为PLL输入时钟9 o5 X) s$ O& f: I* b9 N
1:HSE时钟作为PLL输入时钟。
. f- X% s) G" N1 y, l7 {以上是手册里说的
hhhhhhhaa 回答时间:2020-4-29 15:16:47
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE| RCC_CFGR_PLLMULL9);
" n* L0 a; \5 a# P/ X这句话是不是把相应的位置1 这样就能配置了

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版