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

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

[复制链接]
TLLED 发布时间:2018-12-8 14:43
本帖最后由 TLLED 于 2018-12-8 14:42 编辑 0 G; e" y9 ]! I! P" u
! }9 s: Z7 a! [$ Q6 z, A
    通过第16章节 -- RCC-使用HSE/HSI配置时钟  的学习来重新认识系统总线和外设时钟的配置。 0 y: E, R& ?" R9 K5 p9 Y0 m; g

$ D4 L6 F0 ]. h* l    一、手册中有关时钟配置的内容- {8 B( L: j( R5 {  ^$ b
1 W# @# N0 z( p/ Z6 m) L% ~; Y) R

/ B! {5 E" @( e/ I7 _2 _) [    1.1、系统时钟框图:
5 ~: ^; U4 z# M9 l* {         里面显示出STM32芯片所有时钟和有关配置的寄存器位              1.png
, n# v8 |2 U& u, @/ E: T* F
' E# T( Z5 [% Q9 ]2 A, X8 I   
$ S) l7 p7 z0 @2 _8 J. z4 ]" X    二、系统启动有关时钟配置代码

! V3 W: m0 j1 n' W; M
, r: Q% I3 |; x7 J0 w    2.1、系统启动分析: q$ B* @  F  a5 `" m
        上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
: r) X, S( v# X- Q5 U5 N/ D         100.png , l( s$ |. e/ v5 m' u" O- U
         里面有执行SystemInit系统初始化程序, z9 G6 t% o) N/ Y
        
101.png - t# d, k! d& G1 p# O
         102.png + {* w8 [: e$ E9 S
         103.png
       里面调用SetSysClock函数设置系统时钟) `5 o( {* b( X$ J/ N( h
       104.png       - K* e% ~9 W  i  H2 U
       SetSysClock函数配置为72MHz后调用SetSysClockTo72函数5 t+ T9 i. t& c7 [5 H9 }
       105.png
# D! v. h0 f) D% Z: K$ y' P4 }       106.png
$ X. ]2 H/ [, u) Y: d8 J" C       107.png

  p6 C4 `3 ^$ ^1 g       108.png . i% w% c# w: b
        上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。

* ?. q8 @& W/ q! j3 c: T0 ^$ O8 H  B   
2 t+ N8 N3 S( x    三、时钟配置实例: f1 w. b4 ~$ G1 s8 h. C
& O2 Y& ?( _( f5 j, c3 \! q
. E. z$ N' w+ C( e
    3.1、配置HSE时钟  
7 u6 O3 p4 |6 N, v! l" M% e        了解系统时钟配置流程后,来实践使用时钟配置。0 a$ A' z0 t* G. b1 Z9 x$ i3 y2 O
        在系统时钟框图中,HSE时钟配置, i& P# z6 @5 R8 S' i  T1 L
         109.png 7 X6 K: N- ], ?$ m4 K
    >选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振# Q1 ~( H" y+ l) G5 j
    >通过PLLXTPRE来选择HSE时钟不分频还是2分频。
5 i' K3 [, S- s3 {# W5 E* ]3 J    >通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。+ |3 [/ o% `: j- L4 {+ i& w& K
    >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz
; d. Z, g2 I& K, L/ E
    >通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。9 @. P; _) q( s5 q# _) U3 X

; j* h+ H8 @. J' M. s
/ Y# v# Z. Z  M6 ?# N
    3.2、程序源码  E$ g- t- H  U/ H5 a; _  t
         3.2.1、HSE时钟初始化# k" j: q$ a: C' G2 ^# N
         PLL时钟倍频到72MHz
  a3 f. f- l8 }. O   
  1. static void HSE_SetSysClock(void)' a2 Q$ U$ B) }, C$ e  k
  2. {6 G% A% c. `! e6 w1 ^+ y
  3.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    . ~" c7 M+ n% y+ j* j# _
  4.   8 f7 u! J( N1 I: F& ]- y
  5.   RCC_DeInit();                                                                                        //RCC恢复默认状态    O; ~. R# l/ {3 h8 c' ]8 P6 v: Y
  6.         RCC_HSEConfig(RCC_HSE_ON);                                //打开HSE时钟
    # j9 V! n" J, o4 f7 w
  7.         $ a/ z" N9 H' C$ y/ O2 ^- t
  8.         HSEStatus=RCC_WaitForHSEStartUp();   //等待HSE时钟稳定
    8 j" E: D; x# D3 ~
  9. . l9 J1 r  B4 e: _- E) q
  10.   if (HSEStatus == SUCCESS)
    % l: w; n% k, {3 N& K5 I- A/ i4 k  R
  11.   {7 m- Z1 j; b+ g; A
  12.     /* Enable Prefetch Buffer */3 X2 p6 h) N$ D6 t
  13.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);            //使能FLASH预存取缓冲区: O: A0 s; {; q0 e; `( g
  14.                 FLASH_SetLatency(FLASH_Latency_2);                                                                                               
    - M, W+ e- P; \1 Y) v; S

  15.   \6 `4 e0 t1 S$ `4 k3 d2 q' Q
  16.                 RCC_HCLKConfig(RCC_SYSCLK_Div1);                                                                                                        //AHB - HCLK=SYSCLK' v. `0 w& u6 t: |. y
  17.                 RCC_PCLK1Config(RCC_HCLK_Div2);                                                                                                                //APB1 -- PCLK1=HCLK/2
    " p% s2 l2 ^( x
  18.                 RCC_PCLK2Config(RCC_HCLK_Div1);                                                                                                                //APB2 -- PCLK2=HCLK
    8 N3 h4 z' a5 u3 |% \; ~% e

  19. $ k6 H2 x1 F  j' @+ s
  20.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                        //PLL倍频
    4 I( }/ C' J7 A" ^9 s: h
  21.                 RCC_PLLCmd(ENABLE);                                                                                                                                                                //使能PLL4 L  o8 Z7 O* B0 E' M- J
  22.                         3 k! [/ ?1 D5 f
  23.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)                                        //等待PLL稳定
    8 f, _3 w4 J3 {$ X0 u( h0 S
  24.                 {2 k/ Y# G' H4 c6 M: ~* g7 d
  25.                 }. I( D# o# S9 g0 @* ?
  26.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                                                //PLL稳定后,时钟切换到SYSCLK& Y5 k6 o' m, G. e
  27.                 1 u( V+ q1 ^2 e9 p
  28.                
    9 o) l7 |- K- U/ r/ ^
  29.                 while(RCC_GetSYSCLKSource()!=0x08)                                                                                                //读取时钟切换状态位,确保PLLCLK被选为系统时钟
    . h: h, ^! N3 G* x
  30.                 {: |" x: n0 b5 l  W
  31.                 }3 v0 ?! g  {$ V" d
  32.   }8 c  {+ p/ z1 w, Z' j4 N
  33.   else
    ; B( a; j) X' T& r# B: M
  34.   {
    " w3 w! W' U1 C4 i; B! L. S
  35.   }
    5 R' p8 l; \& S+ C7 b* h
  36. }
复制代码
       3.2.2、MCO引脚初始化5 i& f: Y4 n: W7 ^3 @0 B& d
  1. //MCO引脚配置
    . l8 S/ v0 F  V
  2. void MCO_GPIO_Config(void); [; Q/ y! T  X/ \5 E
  3. {8 Z- w7 t2 `+ ?, L: ~, F5 w( b6 V
  4.         GPIO_InitTypeDef  GPIO_InitStructure;
    ) e) m% N/ z  T- M
  5.         ( @  v1 \* D8 |+ V% [1 k' S
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);                 //使能PA端口时钟; N1 m- i4 w1 G% R- N( v
  7.         6 X% I: z. L: z; m, l* ?. Z/ Y
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;                                                                 8 Y  y( J& L. X' p1 {7 D' X
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         
    % w, {& o8 p/ Q: f6 R; J
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //IO口速度为50MHz
    ; D0 F" }* }  d1 S9 r
  11.         GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                
    3 u0 r+ r' q. ?0 m2 S$ h' f
  12. }
复制代码
       3.2.3、LED引脚初始化
! z* j0 i+ I$ k1 i
  1. 4 L% K: p7 c6 i1 m5 a
  2. void LED_GPIO_Config(void)1 m3 n- G$ B, X5 a
  3. {; I$ F6 p! }; q
  4.         GPIO_InitTypeDef  GPIO_InitStructure;
    7 {$ p$ G# G- ?; J- L3 v& y/ x
  5.         7 X: E. M9 m# ]* _
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);                 //使能PA端口时钟
    ' a3 N5 x4 J+ i
  7.        
    6 _7 R7 j5 s% o1 e
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                                                                
    : e6 x$ f5 L" ~( A  j' v
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                         
    " w- T+ P- Y1 e. ?
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //IO口速度为50MHz
    8 U8 T3 q9 M% u: @
  11.         GPIO_Init(GPIOB, &GPIO_InitStructure);       
    2 l. i, F  x9 C1 e
  12. }
复制代码
       3.2.4、主程序
% q0 h& X9 ?; a& a; d2 N" j
  1. int main(void): m" y: p/ g9 x
  2. {
    ' H. F2 f- f' o
  3.         uint32_t i;
    ( R2 j# x: q8 Q5 z" t" ^
  4.         HSE_SetSysClock();
    " ~4 o# i# m/ v7 t$ a. P
  5.         MCO_GPIO_Config();
    ! x: n/ Z; c0 q. L
  6.         RCC_MCOConfig(RCC_MCO_SYSCLK);        % u. s7 }! y. A1 \  n5 V1 y
  7.         LED_GPIO_Config();        $ g+ d' `) V% l- D5 H) ?4 D
  8.   while (1)
    $ L, M* q. a. T+ V& d- q
  9.   {" e; ]& ]2 @6 h0 K: M
  10.                 9 F- o6 y& U% a6 G- D# @& a
  11.                 for(i=0;i<0xffff;i++);
    % X1 B7 v# f( a5 x/ C& ~! t
  12.                 GPIO_SetBits(GPIOB,  GPIO_Pin_9);- k8 `6 {4 _9 W$ K$ J1 W
  13.                 for(i=0;i<0xffff;i++);6 P& j9 u0 s$ H: t
  14.                 GPIO_ResetBits(GPIOB, GPIO_Pin_9);& U3 U7 @, e% \, ^
  15.   }. [1 a% T' ?' g4 S7 F, b% v  Q
  16. }
复制代码
$ Q: R1 {3 j; ^5 e' n
    四、程序执行结果
8 z4 K" v) z6 h. {# y& H7 n% E2 M, V( ]( _; c

& R" X; ]! L) `0 @: Q    4.1、PLL时钟设置为72MHz,倍频系数设置为98 S4 |& G/ y! J" ?  R9 D! a
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                        //PLL倍频
& v1 D/ L5 l3 }/ p8 W9 {" F9 a        4.1.1、MCO输出时钟频率72M
9 x) i0 q/ ]& s' Q+ Q/ F4 w: o        
F0002TEK.png
7 U' c# v, t9 A' m3 F        4.1.2、LED引脚输出

! V3 A1 m2 U* z8 o1 N! G         F0003TEK.png
! c1 E8 S9 |, H+ N  n0 S
$ k" Q1 ]. A7 S; R  p   
4.2、PLL时钟设置为56MHz,倍频系数设置为7        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);                        //PLL倍频
  ]* u8 S" m7 c2 i) P5 L* }( J        4.2.1、MCO输出时钟频率56M
% J; o  W' V: F5 U$ m8 `7 k         F0005TEK.png
' v3 k/ r( \+ I        4.2.2、LED引脚输出
" _, b) R- \- F& ]9 Q        
F0004TEK.png 1 f) }9 `$ E' L$ ~% h+ D' n
        LED输出宽度比72M时钟时,宽度变宽2 w9 B4 F4 k8 Z; N6 O: i
    4.3、PLL时钟设置为88MHz,倍频系数设置为11        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11);                        //PLL倍频& n* j4 O9 _1 w# r: m
        4.3.1、MCO输出时钟频率88M3 M4 E4 E4 ~2 j
         F0006TEK.png
" E1 x/ z# P9 Q' `; w5 {        4.3.2、LED引脚输出3 o3 ?  z$ E: g2 r( h. p, \# d5 u0 I
        
F0007TEK.png
$ U- J+ H) h+ x: }( E1 M$ H; g        LED输出宽度比72M时钟时,宽度变窄

  g! ]* a/ _8 g5 E, B0 Z% U2 q  U+ v4 @/ a' S
    五、结论
! K4 P& s# P3 J; y* k- g
! T4 u* Q" k! R! D- M

8 L: z1 i5 {4 L  z         使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。
, P% v  _/ h) F) X8 m2 T' t" `% \+ K; ~. J+ f! W

% K: V. J/ \1 I8 K* s8 ]
9 n; f  J( ~9 \' H
2 X5 o, Y: ?6 G  }) J
0 U6 s* g0 |; Y6 K* h# s- m
7 |" _7 E. H" M
% @% l  ~* ^: Z+ n9 a9 ~) `# R

  D9 R* I6 \4 [- P

评分

参与人数 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
您的配置里有这样一句1 l  D9 A) k$ z5 f
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));5 g+ `; I8 m3 V9 \( E! \# o
这句话是把第16-21位清零
hhhhhhhaa 回答时间:2020-4-29 15:06:54
PLLSRC:PLL输入时钟源 (PLL entry clock source)  位16
% {. _) Z3 }2 Q) z- P6 b& G# H* ^由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。1 W) c. m9 o- g
0:HSI振荡器时钟经2分频后作为PLL输入时钟4 W4 o8 C  K) ]5 i$ V
1:HSE时钟作为PLL输入时钟。
  @; ^9 [! k: e  c. v( @以上是手册里说的
hhhhhhhaa 回答时间:2020-4-29 15:16:47
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE| RCC_CFGR_PLLMULL9);
6 e$ S  d' ?1 y1 _* [这句话是不是把相应的位置1 这样就能配置了

所属标签

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