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

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

[复制链接]
TLLED 发布时间:2018-12-8 14:43
本帖最后由 TLLED 于 2018-12-8 14:42 编辑 . J% ^4 W4 k3 O3 M! C" C. J

. C+ r! M, k( C! U' T; W6 `% y    通过第16章节 -- RCC-使用HSE/HSI配置时钟  的学习来重新认识系统总线和外设时钟的配置。   ]+ L$ H- S0 f0 X

0 U) n% l) m/ Q& |: z7 z% ]    一、手册中有关时钟配置的内容
) D- y2 p7 l& B; Q. j+ v! J3 k5 `, ?; B& s+ u

' }* b3 w0 W* L4 @$ t$ n    1.1、系统时钟框图:
! I9 t7 A  {- X+ `7 A         里面显示出STM32芯片所有时钟和有关配置的寄存器位              1.png
9 c' ^9 z% ~* H- c% h5 i" l
6 P2 @, j- l- a+ G, V& K( v) d& [   
2 k6 E: V- i7 p    二、系统启动有关时钟配置代码
, y" V' D+ z; ?. ^0 G

5 O% e) g3 }1 g: x    2.1、系统启动分析# z8 ]2 n9 L, p  S* Y( `3 x
        上篇介绍启动代码分析,会执行Reset Handler服务处理程序。
5 F% [: L- m# w         100.png . y) K  s  O/ W- k6 J- Q
         里面有执行SystemInit系统初始化程序7 {* U; {8 O5 d0 V; e
        
101.png
0 S2 j3 f/ ^3 J- I' K/ \         102.png 7 p0 z8 d# S9 u) r
         103.png
       里面调用SetSysClock函数设置系统时钟' s7 I7 r3 @' R
       104.png       
# k) e9 Z: J+ i( R7 l" {       SetSysClock函数配置为72MHz后调用SetSysClockTo72函数
4 h6 C6 a) I( v3 v       105.png
* b6 \9 \% G' U+ M! ^. K' ]       106.png
0 A1 A5 `. p5 ~2 i       107.png
  B7 h" I- w8 J* u/ ^
       108.png 0 S/ }1 m$ S4 g' V
        上面是系统上电启动中,系统初始化和系统时钟配置过程,已经把总线时钟配置为72MHz。

# n* N: p7 K1 t* Z    ! T8 ^% P  Y8 r& a. u0 r
    三、时钟配置实例3 f" A) k7 M1 Y+ _. @9 w
# |( c7 G1 G+ X
: B6 k8 G' L+ Q, N5 w- b- W
    3.1、配置HSE时钟  - p# b0 u/ [  g& k" I9 Y- o2 ~
        了解系统时钟配置流程后,来实践使用时钟配置。1 Z3 n0 x! S+ I: A# k
        在系统时钟框图中,HSE时钟配置0 S0 z  a4 a; N: H% M" d. b5 d
         109.png
8 f  w; E3 h: W) H    >选择外部时钟OSC32_IN和OSC32_OUT两个引脚上接的8MHz无源晶振2 s+ L( O1 |7 |5 S7 o( S" h
    >通过PLLXTPRE来选择HSE时钟不分频还是2分频。
0 B/ q% {3 s: y  f    >通过PLLSRC来选择内部时钟HSI和外部时钟HSE时钟选择。
9 @% B: p$ E. h6 C0 O/ o    >通过PLLMUL来选择倍频设置,如系统总线72MHz,晶振频率8M*倍频9=72MHz
/ j$ \' x: Z* W6 y* R' Z
    >通过SW来选择时钟源HSI,PLLCLK和HSE时钟源。
; v% O5 i' b' J0 Y  t6 c1 ^) H% z! _: |- ^" |0 X, C1 P

- N" P/ [$ @6 e) e) w# g" ~+ Z8 T    3.2、程序源码. r7 I; |. z1 b4 E& p& i8 d0 l  o
         3.2.1、HSE时钟初始化8 k" c) T4 x. d5 T" b% f
         PLL时钟倍频到72MHz6 U: j" I7 T+ i- Y& s0 }, \  u* C
   
  1. static void HSE_SetSysClock(void): C1 I2 l4 y3 E
  2. {
    4 N/ a  |# }" H9 L- a- P1 v
  3.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;4 }1 {" j! H, X  B; w, x/ f
  4.   
    ) c6 F/ Y. k2 q: r- f8 W7 E" w
  5.   RCC_DeInit();                                                                                        //RCC恢复默认状态  & I8 U2 J( M; T1 P- u% R
  6.         RCC_HSEConfig(RCC_HSE_ON);                                //打开HSE时钟# o6 z! f4 a0 @/ A; C4 o6 x$ X
  7.         : a" z: a" P* r8 h3 e- S8 A/ t
  8.         HSEStatus=RCC_WaitForHSEStartUp();   //等待HSE时钟稳定1 h0 z( q- |& t# y/ E: E! l

  9. 9 M6 H7 j9 `! E( ~. [8 l
  10.   if (HSEStatus == SUCCESS)
    8 _) Z4 ?- s4 A* b# ~
  11.   {
    ) @7 C: [" J% _3 _& @1 R. X' m
  12.     /* Enable Prefetch Buffer */
    : N! g0 E6 V6 S' C* _
  13.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);            //使能FLASH预存取缓冲区
    + Q3 \( `1 H8 h4 z. _; p6 @* l% h
  14.                 FLASH_SetLatency(FLASH_Latency_2);                                                                                                , `5 x# T! ?1 |/ b2 O* P

  15. 5 Q$ k, q5 C9 W" T* y8 c
  16.                 RCC_HCLKConfig(RCC_SYSCLK_Div1);                                                                                                        //AHB - HCLK=SYSCLK% F4 @7 Y3 y( a" b, Y
  17.                 RCC_PCLK1Config(RCC_HCLK_Div2);                                                                                                                //APB1 -- PCLK1=HCLK/2
    5 J. y4 W# `( H8 q
  18.                 RCC_PCLK2Config(RCC_HCLK_Div1);                                                                                                                //APB2 -- PCLK2=HCLK
    9 z2 N3 J, m2 P  a& c
  19. # \2 V$ G9 o6 k( M3 V
  20.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                        //PLL倍频
    5 o+ W( Z& K' e
  21.                 RCC_PLLCmd(ENABLE);                                                                                                                                                                //使能PLL
    , |$ s* \) i& T
  22.                         - Q# X& t# P/ A- I& m4 y0 Z1 Y
  23.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)                                        //等待PLL稳定7 n. j+ C% J% ?, _/ e
  24.                 {' O+ z% v9 E, _. {( \0 h0 T
  25.                 }3 }7 a- K% `( w" x) j
  26.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                                                //PLL稳定后,时钟切换到SYSCLK
    0 R# @. r" @1 {/ Z5 M2 x
  27.                
    * M8 n6 O$ }" I( F# U: R  n  I
  28.                
    , ~* H6 t0 E0 @; f
  29.                 while(RCC_GetSYSCLKSource()!=0x08)                                                                                                //读取时钟切换状态位,确保PLLCLK被选为系统时钟
    5 M: f' m$ _( Y) t* A
  30.                 {- G4 u8 e  [( n8 Y, T7 ^( c
  31.                 }6 p- o( |- ?5 e7 i8 w
  32.   }8 o, j" n; O8 O$ F% c9 ?
  33.   else& p5 v  |& E1 b. P7 ?/ W* U( q, l
  34.   {; f4 v! c3 P7 r: [8 M
  35.   }9 e& d% d8 @; i: ?
  36. }
复制代码
       3.2.2、MCO引脚初始化! S& R# |3 g% }4 ~7 j
  1. //MCO引脚配置
    + v. E& l  a1 }6 e5 |4 q
  2. void MCO_GPIO_Config(void)
    6 E8 L( `& D3 f: g2 s% }( j) _
  3. {
    % ~  Y3 t& _$ m9 P8 O! }* o
  4.         GPIO_InitTypeDef  GPIO_InitStructure;
    ' R' _9 u7 K8 w4 g5 ^9 d
  5.        
    - @# V+ h: }5 ]" Z/ Q
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);                 //使能PA端口时钟
    : Y( P3 G' \; o9 m6 h. F+ o
  7.        
    $ J$ E5 b. Y1 Q2 I' l
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;                                                                
    7 {5 @$ K  [: R% U
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                          7 i1 R. q, K' O3 _
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //IO口速度为50MHz
    ; f" i% A. M0 U) {: [
  11.         GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                   {) t" G7 _# Y/ l! v6 j
  12. }
复制代码
       3.2.3、LED引脚初始化
  v8 ^6 T6 x/ `9 m

  1. + T' ^; C' c/ ?! }- L- G! M- w
  2. void LED_GPIO_Config(void)
    $ X0 U5 [6 r* u9 l& Z
  3. {- J' Y8 I2 @8 I4 w
  4.         GPIO_InitTypeDef  GPIO_InitStructure;
    : V* A9 w# h5 ^7 u
  5.         ( D  M9 ?* r* S* R# C6 Y+ o
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);                 //使能PA端口时钟
    ! v6 `  m, v7 o' e1 s
  7.        
    9 {8 A, F5 p8 c9 c3 T$ r
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                                                                
    8 M/ o3 K6 T, ~& D
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                         
    0 K' F) Z& O" |7 S# a8 u' W) u; M
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //IO口速度为50MHz
    ' y5 I7 A& g# c6 h' q# }! Y
  11.         GPIO_Init(GPIOB, &GPIO_InitStructure);       
    6 h* x3 i3 x. H5 x! N7 _$ [
  12. }
复制代码
       3.2.4、主程序& _8 x0 q# J" ]$ W7 d0 L( ^  y
  1. int main(void)
    / J9 Z& P" X* E
  2. {, H: W  x- h& S$ `* H- B2 h2 ~: I; w
  3.         uint32_t i;: o1 V( Y* O  w8 p* l
  4.         HSE_SetSysClock();
    1 Z1 k  g0 E& N) F2 _
  5.         MCO_GPIO_Config();" W! w7 j! M6 N- a8 b- `: o% p( d0 ^
  6.         RCC_MCOConfig(RCC_MCO_SYSCLK);        $ m  K6 t, n5 h; d( B, ?8 E5 t
  7.         LED_GPIO_Config();        $ ?$ a- b/ }+ X' @! w  x
  8.   while (1). x3 N7 x# c! t
  9.   {, D& h; {6 l: o5 x0 t: n. V
  10.                
    8 J- j1 {0 U  Q$ R1 {
  11.                 for(i=0;i<0xffff;i++);
    ( E  a) M2 A5 I
  12.                 GPIO_SetBits(GPIOB,  GPIO_Pin_9);9 ]& W& Z& v6 R" F, ^" b  v
  13.                 for(i=0;i<0xffff;i++);
    1 L" Y# w0 k: e6 q; ?7 [
  14.                 GPIO_ResetBits(GPIOB, GPIO_Pin_9);, c  m% j- ?( w+ S1 c& \
  15.   }
    . U% P5 ?2 {! X5 K0 g1 w
  16. }
复制代码

8 x" I. q: V$ [# E# R, D- ~5 G    四、程序执行结果) g# N9 p; B, H1 n% L: b! \

* G. y: ]4 r/ Q: C, u6 W

$ B9 P5 {. K% ~0 G6 A    4.1、PLL时钟设置为72MHz,倍频系数设置为9' c0 w1 [# Z0 f5 E8 @
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                        //PLL倍频
* M$ z" B7 ^( [. [1 z        4.1.1、MCO输出时钟频率72M
" S) a2 b( v6 |        
F0002TEK.png
. K2 ^* m" c" V3 ?: N        4.1.2、LED引脚输出

( J% s, U' s4 B* N7 n, C, M         F0003TEK.png
1 i- @) r1 k2 n2 j
5 R9 e* X! S6 ^   
4.2、PLL时钟设置为56MHz,倍频系数设置为7        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);                        //PLL倍频4 k) Z. o6 H, b2 |% B
        4.2.1、MCO输出时钟频率56M9 w- X5 H% _' R4 |. d# T: @
         F0005TEK.png 6 h" C* S% p1 B9 m! O
        4.2.2、LED引脚输出
  `7 Z9 _' [- t        
F0004TEK.png
7 R8 Y) j7 c) n. h        LED输出宽度比72M时钟时,宽度变宽2 }7 t3 `0 ]3 d* k8 g! }; h
    4.3、PLL时钟设置为88MHz,倍频系数设置为11        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_11);                        //PLL倍频# O- h9 w: q1 M" t# n2 `8 K
        4.3.1、MCO输出时钟频率88M
( {, _* j$ R( B  b" z1 R         F0006TEK.png 0 j  G+ o8 E$ j- o2 B
        4.3.2、LED引脚输出
. N' Z& R2 X) B        
F0007TEK.png
* P, d6 w5 G2 T! g3 @  d        LED输出宽度比72M时钟时,宽度变窄
1 y: ~/ f* F7 e# y7 X
1 O& r* F0 d5 S0 T1 Y, H- l* _
    五、结论
; K, g4 f$ O+ D* e/ X7 C
' K7 [7 O. {! w1 Y; E5 u
% w$ A! U0 f  [
         使用外部时钟时,通过改变PLL的倍频系统可以改变SYSCLK时钟频率,来降频或超频工作。HSI配置和HSE差不多,就不在列出。
3 y& y7 E8 O- s8 p: W0 ^
& O9 k5 j, v0 j$ `* o- D8 r
2 F) S( X8 k$ {' _8 m8 n6 I+ |1 l% W+ \9 e/ q' X7 }

0 J' M% L* f! n7 w

7 t5 T6 a3 F% A  ?# t- t) J9 x
/ S4 _! w1 [, H: l& {1 @) C4 j8 I) P5 h0 q* E  X' w  u7 H
0 O" d# M# B2 a# W$ y+ h5 ]

评分

参与人数 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
您的配置里有这样一句! S/ e3 U" z, Q9 k4 L; _  f
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC |RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
8 d4 l( ^6 G& v5 {# @这句话是把第16-21位清零
hhhhhhhaa 回答时间:2020-4-29 15:06:54
PLLSRC:PLL输入时钟源 (PLL entry clock source)  位16, O( c/ o8 q/ h! t5 Z8 F' m
由软件置’1’或清’0’来选择PLL输入时钟源。只能在关闭PLL时才能写入此位。
# y+ i' W; c! g" c, I0:HSI振荡器时钟经2分频后作为PLL输入时钟+ \+ R( [( Q/ U/ A8 S; R7 {8 D; q
1:HSE时钟作为PLL输入时钟。
: A% U0 a$ X9 I& b以上是手册里说的
hhhhhhhaa 回答时间:2020-4-29 15:16:47
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE| RCC_CFGR_PLLMULL9);
/ \! N5 ~, L5 b这句话是不是把相应的位置1 这样就能配置了
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版