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

基于STM32时钟系统经验分享

[复制链接]
攻城狮Melo 发布时间:2023-11-4 19:02
1 STM32的时钟源主要有:
( X/ x. t3 V2 k' V! f0 i内部时钟/ ^( O3 o% q8 g) \
外部时钟; K6 _$ w5 T4 p; y: e) B3 N
锁相环倍频输出时钟
- N: ^: W5 d( R6 s, y6 [
微信图片_20231104190126.png

2 z, v! {3 O* G
$ o2 a* k1 Y6 N$ ~( \2 n; s1.1 详细介绍

0 v+ p9 p( Q5 ^7 b; l/ q8 uHSI(内部高速时钟)" c2 e# r/ |0 G8 O) u
它是RC振荡器,频率可以达到8MHZ,可作为系统时钟和PLL锁相环的输入$ D( ]' N" G+ }5 P
6 z' M# @) E8 U  r2 q* a" T2 b5 h
HSE(外部高速时钟)
8 g* E& X, c* q5 q9 \& R接入晶振范围是4-16MHZ,可作为系统时钟和PLL锁相环的输入,还可以经过128分频之后输入给RTC。
9 D; d7 h. P+ _; Z
/ a: o. b% z4 \( V
LSI(内部低速时钟)
, X- R0 P& R& R) h6 \' {0 K" M, r它是RC振荡器,频率大概为40KHZ,供给独立看门狗或者RTC,并且独立看门口只能依靠LSI作为时钟源% V% a! m- M4 `+ Y. z1 d3 ]4 k
% B0 B; U4 i; T6 \0 o" ]$ R$ W
LSE(外部低速时钟)/ f) ?& h8 |) g7 x7 m& F5 j7 e
通常外接32.768MHZ晶振提供给RTC; e3 o, S. @2 x2 b

& ^  G7 B- r- n7 W9 V5 e6 b7 `
PLL(锁相环)# J$ y' B. N, K
用来倍频输出。因为开发板外部晶振只有8MHZ,而STM32最大工作频率是72MHZ。他可以通过HSI输入,HSE输入或两分频输入,通过PLL倍频(2-16),倍频之后输入给系统时钟。
0 ^* M- y$ E* @' t
  q. x4 L9 h4 z* {, f& h, ?) a
MCO(时钟输出管脚)
& w' ^6 P3 n. J通常对应STM32 PA8,它可以选择一个时钟信号输出,给外部的系统提供时钟源7 A8 k, C! p& S% D4 d' f1 v0 b

0 F- r" `% v2 G8 `8 t
2 标准库的时钟配置
$ Q# c4 s7 b8 u1 |' l4 ^# n2.1 STM32启动文件
" w* d) d* [: [$ H" ]
首先打开startup_stm32f10x_hd.s,该文件为stm32的启动文件,在该文件内会发现有这么一块用汇编写的代码。
2 J1 n* Q& @7 K2 U4 H
  1.       Reset_Handler   PROC
    9 a' G. r* t/ L1 p$ F: l+ ]
  2.             EXPORT  Reset_Handler    [WEAK]
    3 u5 V" P. {9 K# K4 i2 J9 E
  3.             IMPORT  __main
    ' P' `% T% D! u0 @8 H; Z6 m
  4.             IMPORT  SystemInit' j* ?: T# k/ Z/ ~
  5.             LDR     R0, =SystemInit
    * A% c9 T( w9 b( `: w; S
  6.             BLX     R0               ) [2 H( G; W2 ^
  7.             LDR     R0, =__main% {& r! a; ], @5 g) |' o
  8.             BX      R0
    4 z1 l. [! f6 F) L4 q& p
  9.             ENDP
复制代码
8 v/ L+ p9 r# L" P
通过这段汇编代码可以看出,程序在执行main函数之前,会先执行SystemInit函数。
, I+ \; v3 B  U4 R( h. f, U
3 Z) I  C2 F' W! h
2.2 SystemInit函数详解
  1. void SystemInit (void)
    " f6 e3 A* z  z( O) \* |1 i6 b
  2. {
    " a; b1 |2 i9 X! T
  3.   /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
    8 C0 v1 q9 p' }, s; M+ U2 p8 T
  4.   /* Set HSION bit */+ \' I% L9 e/ E# x7 R
  5.   RCC->CR |= (uint32_t)0x00000001;, P9 X7 S% H0 Y/ @- ]
  6. ( W$ M5 A0 O( g' j" y/ v
  7.   /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */( b8 B+ k# O7 |) l# g1 j2 l
  8. #ifndef STM32F10X_CL( C& P7 i2 X9 v7 l! e6 K; N3 V, {% x& e
  9.   RCC->CFGR &= (uint32_t)0xF8FF0000;, b6 H5 E  e; j" t9 f
  10. #else  V) A& y9 B8 X% ~$ t7 C+ `! E
  11.   RCC->CFGR &= (uint32_t)0xF0FF0000;
    % Z8 a' x! z( |) R: P! W2 J* f
  12. #endif /* STM32F10X_CL */   
      @2 A# O# ^$ G, R3 ]5 h/ ^5 B

  13. + e7 [4 d5 G4 U8 n
  14.   /* Reset HSEON, CSSON and PLLON bits */
    4 q/ W& i& t! s$ T) i  o3 o
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;
      U2 f- E& m" \3 X! M. c* R

  16. 0 @3 C' ^( \4 c: p4 ?, F$ {1 z
  17.   /* Reset HSEBYP bit */  p+ V  }/ R2 I2 b' F7 c. _! H* x
  18.   RCC->CR &= (uint32_t)0xFFFBFFFF;" Q, M# v* Q* J$ p  j- `4 u
  19. " v; ~* s* o! G! ~" f
  20.   /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
    ' D, V) Q5 c% \$ f( a2 X/ W, T
  21.   RCC->CFGR &= (uint32_t)0xFF80FFFF;
    0 Y2 E# g3 d" {8 E2 Y4 ]
  22. 3 f( F1 y) R3 k$ O6 W% P" C7 I  }
  23. #ifdef STM32F10X_CL: h5 D3 Y. W6 }3 Z9 p2 e9 i
  24.   /* Reset PLL2ON and PLL3ON bits */
    8 s- s. q0 J$ `* x7 \
  25.   RCC->CR &= (uint32_t)0xEBFFFFFF;
    + e1 Q, J# o6 z) H' ~% F. y

  26. % P/ w" h7 j8 G+ F7 L- M% k+ z
  27.   /* Disable all interrupts and clear pending bits  */0 P- f4 A5 p7 M" r- p  h* C  r. v
  28.   RCC->CIR = 0x00FF0000;$ r6 c0 k6 w. V  I0 O

  29. ' v, H$ |0 M& V- x
  30.   /* Reset CFGR2 register */
    . h1 R# T9 k' o
  31.   RCC->CFGR2 = 0x00000000;# D+ y$ X, u1 X% H# I( r' H2 E5 x
  32. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
    2 v7 U3 s% T7 n& _' I
  33.   /* Disable all interrupts and clear pending bits  */
    ; P. p* b2 d' H( M% ^& V$ I
  34.   RCC->CIR = 0x009F0000;
    , [) m+ U# R2 w: X
  35. # M* _6 x* F4 E/ r/ n+ {
  36.   /* Reset CFGR2 register */& ?8 Y# Q% z5 y8 W9 g4 I
  37.   RCC->CFGR2 = 0x00000000;      * |' U% ]: R8 f& t" b' P0 @
  38. #else
    $ ]2 q  D7 X/ O
  39.   /* Disable all interrupts and clear pending bits  */
    0 f; m! o* ~* f5 `
  40.   RCC->CIR = 0x009F0000;
    1 l/ W9 m% h8 g1 `) D- w+ S% [
  41. #endif /* STM32F10X_CL */. w6 T+ D) k" R: T& h
  42. ) g8 H0 w# {) q" Z; @; m
  43. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)+ J3 f$ W7 y- I/ l) v! a* ^
  44.   #ifdef DATA_IN_ExtSRAM
    5 }# H$ {* {5 H
  45.     SystemInit_ExtMemCtl(); # w" u/ z' N, a% a' n1 a
  46.   #endif /* DATA_IN_ExtSRAM */
    / G( W" t, ?) u) ^
  47. #endif
    + Y7 c! `6 o9 \- j
  48. , P* o! i8 A, D7 e  J. Z) B
  49.   /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */: e7 d, r9 F) N
  50.   /* Configure the Flash Latency cycles and enable prefetch buffer */5 P1 S4 P; h* `3 M( L( k( \: \* K
  51.   SetSysClock();8 z" L3 Y6 r' a. r$ F" h2 M
  52. 5 M2 |5 H- L$ x; g! ^/ u) h
  53. #ifdef VECT_TAB_SRAM
    # g0 f" ?& k+ C9 @
  54.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    / K! q, K# ?6 Z) o, t: g7 a  T0 |
  55. #else
    2 B" z) q9 J: ~9 N! y5 X- k8 O
  56.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
    . }; y, F+ Y* f. G' z/ E
  57. #endif 5 q1 M  W+ D: v* y
  58. }
复制代码

# d( H, G" T7 y7 b  S9 l% F/ ^8 N9 p, x& G" e
打开内部8M时钟:( q; z! Z$ G( \! E4 c2 q+ v' ?
  1. RCC->CR |= (uint32_t)0x00000001
复制代码

" D7 i0 Z; H2 b, Q通过查看寄存器手册可知,这段代码为打开内部8M时钟。
5 K( [# o8 m- e5 E3 F* ]% |- V+ {  J; y7 n9 d+ c* X
微信图片_20231104190120.png

" e4 n) l" G7 q6 D* c, t
) k) e$ K+ j9 c  i设置时钟配置寄存器:
, V6 o- T2 i/ ^: r0 \9 `9 T& r3 R) O
  1. #ifndef STM32F10X_CL- T9 \0 h6 X- b+ s% t, X
  2.   RCC->CFGR &= (uint32_t)0xF8FF0000;
    . ]* Y# I+ v$ |0 s
  3. #else
    % E1 t6 A! i& ?# B, f
  4.   RCC->CFGR &= (uint32_t)0xF0FF0000;* U& I# C( U; ]6 ^
  5. #endif /* STM32F10X_CL */   
复制代码

3 E8 q/ }! G. e- ]  ~  ], H* t对应寄存器说明可查看《STM32中文参考手册_V10》的6.3.2 时钟配置寄存器(RCC_CFGR)章节。5 B( S5 y# @" u/ k
后续代码,有兴趣可根据《STM32中文参考手册_V10》手册,查看代码具体作用。7 D( I+ M5 G# u$ A

- N! I" J) L$ N$ I8 u8 z$ s
2.3 SetSysClock()函数详解
. F; a* c- }5 [/ o. w
  1. static void SetSysClock(void), d: c0 N! d# T7 U3 q
  2. {: S7 p1 Q+ h4 y( E# f% L, B" y2 S
  3. #ifdef SYSCLK_FREQ_HSE' y( ^: E; s: z/ z* h( u* k3 b
  4.   SetSysClockToHSE();2 C# l3 Z5 D1 H/ M
  5. #elif defined SYSCLK_FREQ_24MHz% r  q0 R! M+ l( O9 N
  6.   SetSysClockTo24();
    $ ^7 |  r, Y2 k& C1 i, B. h2 Z
  7. #elif defined SYSCLK_FREQ_36MHz
    " J7 t: m; Y; M* s
  8.   SetSysClockTo36();6 R9 |+ w( }0 U" Y' ^/ d9 r2 k. l7 R
  9. #elif defined SYSCLK_FREQ_48MHz& V# e9 H5 V7 V5 o
  10.   SetSysClockTo48();) V3 I; F8 a$ e1 d
  11. #elif defined SYSCLK_FREQ_56MHz
    ' V' ^0 [3 C+ h4 m' _
  12.   SetSysClockTo56();  
    ' M, u! z, |7 k7 g! p
  13. #elif defined SYSCLK_FREQ_72MHz
    4 d5 m& R. r1 N0 H  i
  14.   SetSysClockTo72();
    ( a: ~) H! F* [$ |& Q3 `% S- d1 L
  15. #endif2 g! {8 q" F) @* N0 W: e! l
  16. }
复制代码
5 P0 A0 D( p, N6 ~. M1 {% q

  h0 p9 h7 x8 B8 Q% esystem_stm32f10x.c文件中会根据芯片的型号定义对应的宏:# t2 ~6 u, H9 s. d# o2 u+ a' s
  1. #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)# X. p- |& s! p5 ^  w; h( C5 p$ V
  2. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */7 `1 H$ [; J4 U, g9 {" ^* @
  3. #define SYSCLK_FREQ_24MHz  24000000
    & @" \' I  S; K" ^9 G( @  g% C6 U
  4. #else
    ) [, ?( [; c- t$ ~
  5. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
    7 F' O) M$ p' w8 \2 h( [( V
  6. /* #define SYSCLK_FREQ_24MHz  24000000 */ + Z) X& ]0 P4 ]
  7. /* #define SYSCLK_FREQ_36MHz  36000000 */; i4 n0 f- J5 D2 J9 V1 ]* G
  8. /* #define SYSCLK_FREQ_48MHz  48000000 */. Q; S9 K6 O" u
  9. /* #define SYSCLK_FREQ_56MHz  56000000 */
    / V2 J& i& d6 g$ n* K
  10. #define SYSCLK_FREQ_72MHz  72000000
    - g9 x% e5 U+ t8 v  W
  11. #endif
复制代码

2 ]3 ^  T% G' _9 L  p/ H3 时钟配置函数* h! F+ M; E5 k. A6 L$ I5 H" G
3.1 时钟初始化配置函数
  1. void SystemInit(void);
    5 V  f, a+ t) W% k
  2. SYSCLK(系统时钟)=72MHZ;. ?: a- e4 K, b9 G+ N3 k
  3. AHB总线时钟(HCLK=SYSCLK)=72MHZ;
    + Q; }. e$ s" ?3 C! U3 S6 E/ d9 N
  4. APB1总线时钟(PCLK1=SYSCLK/2)=36MHZ;
    9 _$ L7 ?! Z+ ^0 g3 h
  5. APB2总线时钟(PCLK1=SYSCLK/1)=72MHZ;( J6 A* M2 \+ D3 K+ E; T
  6. PLL主时钟=72MHZ;
复制代码

$ d: {: o8 C# @6 o+ {4 G2 V1 F. S0 q
3.2 外设时钟使能配置函数
: M$ _- [% P5 b) K, }1 a
  1. void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);% l* H' p6 W; [. m7 k+ q
  2. void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);6 i' ?% e& J% m
  3. void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
复制代码

' \$ W% ^' O9 ^! {! g" B3.3 时钟源使能函数
  1. void RCC_HSICmd(FunctionalState NewState);
    5 L" ?2 `6 ^! i& j* L
  2. void RCC_LSICmd(FunctionalState NewState);
    ! L* h- ?7 s5 d* ]# X' P5 L
  3. void RCC_PLLCmd(FunctionalState NewState);  C$ Z# V6 y# I4 t
  4. void RCC_RTCCLKCmd(FunctionalState NewState);
复制代码
) [6 O5 k' ?# e+ w" i* C
, o6 ]$ d& X9 _# @
3.4 时钟源和倍频因子配置函数
: g9 Z4 i  L. w+ N
  1. void RCC_HSEConfig(uint32_t RCC_HSE);: H7 d; r3 i7 D) q7 p- ?8 {8 O. a& H: t
  2. void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
    % I. x; ?7 T4 U2 {0 _
  3. void RCC_HCLKConfig(uint32_t RCC_SYSCLK);! q; [0 u+ N$ D
  4. void RCC_PCLK1Config(uint32_t RCC_HCLK);' l1 \- G% Z) L, _1 ?  o. i
  5. void RCC_PCLK2Config(uint32_t RCC_HCLK);
复制代码

  R# s9 E8 ]3 S  e7 G. h. ^! |3.5 外设时钟复位函数$ A5 {, |& L& Y6 P% {: \0 i
  1. void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);& T: i, `9 @" k- o% ]
  2. void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
复制代码
/ [0 v- y1 G: p4 }, H' b
3.6 自定义系统时钟
. {$ o- b$ Z8 m; I4 K& z# V6 f
  1. void RCC_HSE_Config(u32 div,u32 pllm)
    1 ^) C% z6 E# h3 Z& B* w) W
  2. {
    ! L2 ]0 O8 Y2 D5 a* Z1 L# @* u
  3.     RCC_DeInit();6 H7 G- e0 x" |, D# h; |
  4.     RCC_HSEConfig(RCC_HSE_ON);& k7 b: Q" n/ L$ Y
  5.     if(RCC_WaitForHSEStartUp()==SUCCESS)
    4 W5 k$ ^* s4 s( {* s/ [3 H1 c0 F2 j" R
  6.     {   7 }3 C/ d6 X' z0 a4 g" T' L
  7.         RCC_HCLKConfig(RCC_SYSCLK_Div1);
    & ]/ `( j( i/ v+ a. o0 ]
  8.         RCC_PCLK1Config(RCC_HCLK_Div2);$ ]9 ?: ]0 b/ {5 E
  9.         RCC_PCLK2Config(RCC_HCLK_Div1);
    3 j2 G& H' P6 g; [
  10.         RCC_PLLConfig(div,pllm);
    4 G% z0 s3 `% n3 T- V* e$ g
  11.         RCC_PLLCmd(ENABLE);     
    , x6 Q0 M" B4 L; h
  12.     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
    ; B2 L+ o  ^3 r2 ?+ u9 P+ a
  13.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)6 O0 @/ {+ D1 c1 q8 y
  14.     while(RCC_GetSCLKSource()!=0x08);
    1 W9 V. q' E7 E* X. q3 o

  15. & ~2 G  F8 o4 E+ c) K5 B  G6 M
  16.     }
    + E7 |' n3 M- F8 Q  A9 _2 w% s
  17. }
复制代码
转载自:STM32嵌入式开发/ P& |# x8 s4 ]5 K/ H9 U

5 t2 |6 L! g- Q: J& D6 Y* E3 [4 k如有侵权请联系删除
" d5 `5 Y2 Q  j) D6 d: z, w) O3 F1 d) ~
赞 收藏 评论0 发布时间:2023-11-4 19:02

举报

0个回答

所属标签

相似技术帖

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