|
stm32时钟系统的意义: 1、电源的开关作用,达到低功耗效果; 2、调节时钟的速度; 对于每个外设,都要设置设置,stm32的时钟系统为了更低功耗; STM32时钟系统框图分析:
* f a3 ~! F- | V& X2 |
3 B& |) G& P. p) O1 `% u# O2 B# W时钟源: 时钟是STM32的脉搏,是驱动源。使用任何一个外设都必须打开相应的时钟。这样的好处就是,如果不是用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果; stm32的时钟可以有以下4个时钟源提供: 1、HSI:高速内部时钟信号stm32单片机内带的时钟(8M频率),缺点是精度较差; 2、HSE:高速外部时钟信号,精度高 来源:(1)、外部晶振 (2)、HSE用户外部时钟; 3、LSE:低速外部晶振 32.768khz主要提供一个精准的时钟源,一般作为RTC时钟使用; 4、LSI:内部低速时钟,提供独立看门狗,也可以给RTC; STM32将时钟信号(例如HSE)经过分频或倍频(PLL)后,得到系统时钟,系统时钟经过分频,产生外设所使用的时钟; RCC设置流程: 1、将RCC寄存器重新设置为默认值 RCC_DeInit 2、打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON) 3、等待外部高速时钟晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp(); 4、设置AHB时钟 RCC_HCLKConfig 5、设置高速APB时钟 RCC_PCLK2Config 6、设置低速APB时钟 RCC_PCLK1Config 7、设置PLL RCC_PLLConfig 8、打开PLL RCC_PLLCmd(ENABLE) 9、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) 10、设置系统时钟 RCC_SYSCLOCKConfig 11、判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource()!=0x08) 12、打开要使用的外设时钟 RCC_APB2PerphClockCmd()/RCC_APB1PeriphClockCmd() 实例: - /******************************************************************************** L& l ^* W- B: q) A& S
- * Function Name : RCC_Configuration
9 i/ ]* `% T; r! P - * Description : Configures the different system clocks.* ?7 P5 E8 ?# ]) K5 l; S3 w& y: D; E
- * Input : None; F8 |; J7 H1 p9 [" O U
- * Output : None
a7 A( W* S! S5 m) | - * Return : None H6 J9 u/ a# o6 ?* y% ]
- *******************************************************************************/# V7 A9 @ i8 S, b, I8 V
- void RCC_Configuration(void)7 L; ?3 a8 k8 w7 p# ~7 B
- {
% ~ X; c4 s/ ]- _ - /*------使用外部RC晶振----------*/
" H" g J% ]% b* q1 z: F+ V - RCC_DeInit(); //时钟默认初始化4 W" v4 k4 R9 j( a% f- J5 C# J
- RCC_HSEConfig(RCC_HSE_ON);//使能外部的高速时钟
2 s! ^: g7 @/ K* k) r - while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);//等待外部的高速时钟就绪& B: }) Z! I5 g) ^1 l* ]0 Y4 ]
- . l. b/ a6 f/ L: I7 V" d
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能指令预存取' P: o- Q& t8 |
- FLASH_SetLatency(FLASH_Latency_2); //等待两个周期4 X5 U' Y2 T$ e+ l
- / ^6 N6 C& t' \, y9 y* o
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟为系统时钟# {3 o; t: ?: \. K1 D
- RCC_PCLK2Config(RCC_HCLK_Div1); //设置APB2时钟为AHB时钟
3 J) l6 B% k3 m. `7 m - RCC_PCLK1Config(RCC_HCLK_Div2); //设置APB1时钟为AHB/2时钟
" \: e P3 S# c; Q4 r - //以下3行是PLL的设置& u& j+ G/ q& G( M {0 \, S& |
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //设置PLL时钟为外部高速时钟的9倍频5 C; Q6 q& b3 p W3 T/ j/ {. h
- RCC_PLLCmd(ENABLE); //使能PLL时钟
1 W$ K/ z" n) Q) R7 i3 j4 [% @ - while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL时钟使能就绪 C) @- e' |% r K0 E* m
- //选择为PLL的CLOCK
9 F3 w- ^& t# B# i' w$ \) s - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //配置PLL时钟为系统时钟
8 b. I" F4 x9 \' ^ - while(RCC_GetSYSCLKSource()!=0x08); //等待PLL时钟作为系统时钟7 v* H/ _' v. z; T8 A, X1 b2 K2 L8 ^
- $ X# i7 T5 r, Z. s1 D- b8 K4 V
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC);* q5 e% a8 V* E
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_UASRT3,ENABLE);
4 a% F3 |7 Z' Z2 t0 F5 N2 k - }
复制代码
. _% }8 F ?" A, t5 {3 Z G# r& ^! r7 @% B+ J* ~! n! a
RTC模块: RTC(Real_Time Clock)实时时钟; 实时时钟是一个独立的定时器,RTC模块拥有一组连续计数的计数器,在相应软件的配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期; RTC由两个主要部分组成。第一部分(APB1接口)用来和APB1总线相连。此单元包含一组16位寄存器,可通过APB1总线对其进行读写操作。APB1接口以APB1总线时钟为时钟; 另一部分(RTC核)由一系列可编程计数器组成,分成两个主要模块; 第一个模块是RTC的预分频模块,它可编程产生最长为1秒的RTC时间基准TR_CLK,RTC的预分频模块包含了一个20位的可编程分频器(RTC预分频器)。在每个TR_CLK周期中,如果在RTC_CR寄存器中设置了相应允许位,则RTC产生一个中断(秒中断) 第二个模块是一个32位的可编程的计数器,它可以被初始化为当前的系统时钟时间。系统时间以TR_CLK速度增长并与存储在RTC_ALR寄存器中的可编程的时间相比较,如果RTC_CR控制寄存器设置了相应允许为则比较匹配时将产生一个闹钟中断;
1 Z& I3 }/ P; k8 F$ a4 `
RTC主要特性: 可编程的预分频系数:分频系数最高为220。 32 位的可编程计数器,可用于较长时间段的测量。 2个单独的时钟:用于APB1 接口的PCLK1 和RTC 时钟(此时的RTC 时钟必须小于 PCLK1 时钟的四分之一以上) 2种独立的复位类型: ─ APB1 接口由系统复位 ─ RTC 只能由后备域复位。 3个专门的可屏蔽中断: ─ 闹钟中断,用来产生一个软件可编程的闹钟中断。 ─ 秒中断,用来产生一个可编程的周期性中断信号(最长可达1 秒)。 ─ 溢出中断,检测内部可编程计数器溢出并回转为0 的状态。
% y8 h/ ~6 O* |1 V, H' c( _9 d % T) @& K' g7 v" a
RTC的一些设置是保存在后备区域中的:RTC_PRL, RTC_ALR, RTC_CNT 和RTC_DIV寄存器; 这些寄存器仅能通过备份复位信号复位,不受系统复位或电源复位的影响; 备份区域复位: 当以下时间中之一发生时,产生备份区域复位: 1、软件复位,备份区域复位可有设置备份区域控制器RCC_BDCR中的BDRST位产生; 2、后备电池和系统电源都没电的情况下;引发备份区域复位; 配置RTC: RTC有两种模式(工作模式和配置模式),要对RTC进行配置,首先设置RTC处于设置模式下;通过对RTC_CRL寄存器中的CNF位置位使RTC进入配置模式;另外,对RTC的任何寄存器的写操作都必须在前一次写操作结束之后再进行,要使用软件来查询当前的状态,同可通过查询RTC_CR寄存器中的RT0FF状态位来判断RTC寄存器是否处于更新中,仅当RTOFF状态位是“1”时,RTC寄存器可写入新的值;(这些是对RTC的保护措施) 配置过程: 1、查询RTOFF位,直到RTOFF的值变为“1” 2、置CNF值为1,进入配置模式; 3、对一个或多个RTC寄存器进行写操作; 4、清楚CNF标志位,退出配置模式; 5、查询RTOFF,直到RTOFF位变为“1”,以确认写操作已经完成; 仅当CNF标志位被清零时,写操作才能进行;这个过程至少需要3个RTCCLK周期; 配置实例:- /*************************************************************************************
, i: r, R* v4 W - **名称 ;void RTC_Configuration(void)
3 a3 J0 h0 |( T1 P5 s* F0 K% ? - **功能 ;RTC实时时钟的配置
# f' n' ~, E; G - **入口参数 ;无" c" H8 `6 C" ^3 c S. ?6 ?3 d
- **出口参数 ;无1 t) m1 P- L _
- *************************************************************************************/
; y& `8 l& _* ]! Z( y& F! a. D+ N - * }0 \ U4 L2 d% v) n8 X
- void RTC_Configuration(void)
3 _9 j5 _ V9 @ - {7 f2 O' E. s `% C& w
- /* Enable PWR and BKP clocks */ //使能APB1外设PWR and BKP 的时钟( |. b# ]" |- w: k
- /*打开电源和后备时钟*/
& H* D" \9 s9 q( R - RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
( Y( M$ \# o0 ?5 [7 p6 J - # A, c5 X# A r0 Q% w- s; F. t/ L
- /* Allow access to BKP Domain*/ //允许RTC 和后备区域寄存器的访问
& O% w& P- O0 \ J/ ?# b* h- s - PWR_BackupAccessCmd(ENABLE);
+ _+ t$ [! N* C - 9 i4 ]! ?- R% l! v1 c6 c
- /* Reset Backup Domain*/ //将外设BKP的全部 寄存器重设为缺省值% o& r' }; M( h: G) J# M
- BKP_DeInit();
! @7 l5 I* M0 c. w: n - - o+ I0 b8 q3 p( p8 b
- /* Enable LSE */ //设置(打开)外部低速时钟; d: n! N, Z5 d$ ?) R
- RCC_LSEConfig(RCC_LSE_ON);1 |* P) b; R: m8 K, x# X
- 0 q+ C& B; c0 ~ D+ a
- /* Wait till LSE is ready */ //等待外部低速时钟准备好
' m6 |9 G1 X1 G1 V - while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);8 E. `6 d) g6 X6 V3 \/ K
- % k0 u( T3 R6 E
- /* Select LSE as RTC Clock Source */ //设置LSE为RTC时钟
( Z4 V: S3 K) P1 a: Z - RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);8 t. O3 i* A# ?: N) F
- $ @! W6 T; y' e8 x: M0 M
- /* Enable RTC Clock */ //使能RT时钟
4 ^8 c# V% h# Z - RCC_RTCCLKCmd(ENABLE);: T E4 ~' A1 i; Z! e
- 0 b' y" r0 `5 V9 L1 g
- //开始设置RTC,下面同步原因是:有两个时钟
# b8 `2 I* x7 g7 E$ Z, B - /* Wait for RTC registers synchronization *///等待RTC寄存器(RTC_CNT,RTC_ALR and RTC_PRL)与RTC的APB时钟同步
u5 T1 W6 s2 E t: P - RTC_WaitForSynchro();
" g; ^- A h L+ z. ^
4 V p7 g5 t) m& u$ n- /* Wait untill last write operation on RTC register has finised *///等待最近一次对RTC的写操作完成, K# n* X" t/ u: I/ q- u
- RTC_WaitForLastTask();' |, z' a8 N' K) G& c, p& l
* G S0 p/ \, M3 q- /* Enable the RTC Second interrup */ //使能RTC的秒中断% c k( F& I) \, }# K1 |; a
- RTC_ITConfig(RTC_IT_SEC,ENABLE);7 h' u7 W8 _* y* Q5 }' {
) d6 j5 L- g( I- /* Wait untill last write operation on RTC register has finised */
' _1 T5 E6 V. ?9 V) d - //等待最近一次对RTC的写操作完成
5 ]; N7 X/ e! T" b5 k - RTC_WaitForLastTask();
; P/ [+ w( ^5 m, M+ A. d - $ g! g6 \5 N6 r0 @9 C# l
- //分频值为32767+1=327689 {- g- f$ Y# u
- //计数频率=(32.768khz/32768)= 1hz
/ o$ F6 ~) r1 W2 S - /* Set RTC prescaler : set RTC period to 1 sec*/ //设置RTC预分频的值
5 N, |. c) @/ g# K6 C8 L - RTC_SetPrescaler(32767);0 z4 ?6 I' N! g8 I9 ?
5 F2 F4 A7 b9 ?3 `0 m- V; h: y- /* Wait untill last write operation on RTC register has finised */
. j5 L n) j* w+ Y: L; y6 p5 N+ K! q - //等待最近一次对RTC的写操作完成
( x o# g( `! G5 r! ~ - RTC_WaitForLastTask();
8 T4 c% h5 p9 D5 Q' d9 H - 3 I: L8 u: j8 K8 B& A3 j' {
- //设置当前的时间值/ [- B8 Z4 l1 H, N: Q+ J8 x
- /*2014.4.5 10:20:49 @9 o2 W8 k1 k* G
- *t = 4+20*60+10*60*60 + 5*24*60*60+
) B, l& |4 U/ W/ d& D - *9 Q. w$ f- {! p; B& n
- */
8 R" K7 [9 U. g- \: R - RTC_SetCounter((u32)t);
0 I& d, J4 r; Y j& C8 f - RTC_WaitForLastTask();
! P7 c) v. m* [, T3 I8 Z6 R - }
复制代码
, K4 S" B7 y. ]; p |