|
stm32时钟系统的意义: 1、电源的开关作用,达到低功耗效果; 2、调节时钟的速度; 对于每个外设,都要设置设置,stm32的时钟系统为了更低功耗; STM32时钟系统框图分析:
) P: D6 \, b; |7 {
: U0 X z/ L8 ]6 z- i, ]时钟源: 时钟是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() 实例: - /*******************************************************************************' Y7 r Z3 E4 D) w/ d# l0 z/ `
- * Function Name : RCC_Configuration
, @% ]0 ] P& @ - * Description : Configures the different system clocks.0 U1 d" @* a: `- G) n
- * Input : None
2 C+ x, i% }' d9 w - * Output : None
8 p4 m6 x/ H B* y; a - * Return : None% J1 ^" Y% ]# O0 `, ~
- *******************************************************************************/8 P# d7 k4 {" z7 M
- void RCC_Configuration(void)
9 ]' Z8 A& f7 G6 p- Y2 A) A4 p0 R - {# j9 |/ x C! i+ p2 D
- /*------使用外部RC晶振----------*/
+ `( |' Z. e+ n+ W% N* N; P - RCC_DeInit(); //时钟默认初始化
' F6 a4 \! V. M, l - RCC_HSEConfig(RCC_HSE_ON);//使能外部的高速时钟7 N9 g% t1 R' l( y, j6 I
- while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);//等待外部的高速时钟就绪
! a+ V- k1 ]! G2 t - ( i: L! N5 Y; t, X$ ?+ c6 n: H: o4 b" Q
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能指令预存取
, H! Y. M" I6 A) [ g) o - FLASH_SetLatency(FLASH_Latency_2); //等待两个周期
7 ~* f( a( M2 b. I* p, I - ' d+ u- J( I# b8 \
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟为系统时钟8 z0 Y) t# s! F5 L% G+ |6 f
- RCC_PCLK2Config(RCC_HCLK_Div1); //设置APB2时钟为AHB时钟4 x0 R: z6 m9 T
- RCC_PCLK1Config(RCC_HCLK_Div2); //设置APB1时钟为AHB/2时钟+ [) y. H f! B4 z6 q! Q% ]8 N
- //以下3行是PLL的设置% X' O& j# a( S+ u, T- s) m1 }
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //设置PLL时钟为外部高速时钟的9倍频. s8 y& `) {) G/ O
- RCC_PLLCmd(ENABLE); //使能PLL时钟
* ?8 S' @. u; L; M - while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL时钟使能就绪
8 Q7 s- s6 e0 U9 P- h3 f; Z - //选择为PLL的CLOCK' Z' |" S \! X- U# o* G' ?- B
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //配置PLL时钟为系统时钟; \: x' F; y7 h1 p) h
- while(RCC_GetSYSCLKSource()!=0x08); //等待PLL时钟作为系统时钟
9 ?7 k& S" \0 f# {5 C9 U. u - 2 ~1 b3 D( F* |$ Q1 f. H
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC);
- M' V- _3 R" H* g6 E d# F - RCC_APB1PeriphClockCmd(RCC_APB1Periph_UASRT3,ENABLE);
" H# x; T. V9 K/ _1 F( J Q, Q% Y - }
复制代码
3 h7 {0 U1 t4 R/ L. l: D) u) G, n7 \; l
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控制寄存器设置了相应允许为则比较匹配时将产生一个闹钟中断;
' q* O6 y# D- \3 ?; b3 _' V
RTC主要特性: 可编程的预分频系数:分频系数最高为220。 32 位的可编程计数器,可用于较长时间段的测量。 2个单独的时钟:用于APB1 接口的PCLK1 和RTC 时钟(此时的RTC 时钟必须小于 PCLK1 时钟的四分之一以上) 2种独立的复位类型: ─ APB1 接口由系统复位 ─ RTC 只能由后备域复位。 3个专门的可屏蔽中断: ─ 闹钟中断,用来产生一个软件可编程的闹钟中断。 ─ 秒中断,用来产生一个可编程的周期性中断信号(最长可达1 秒)。 ─ 溢出中断,检测内部可编程计数器溢出并回转为0 的状态。
9 K& `( d( L) Y& a
3 W1 F( m5 A1 u% f2 iRTC的一些设置是保存在后备区域中的: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周期; 配置实例:- /*************************************************************************************: O$ A- x" W2 V1 Q- X
- **名称 ;void RTC_Configuration(void)7 ?( h2 l+ E5 B& a B
- **功能 ;RTC实时时钟的配置
& p4 Z1 D( l. O - **入口参数 ;无
, Z0 m M8 e+ `) }5 S - **出口参数 ;无+ i I* R- h7 L* W
- *************************************************************************************/- r A; v6 v; X2 |/ p: o
; Q, j5 w# U; |; k; q- void RTC_Configuration(void)2 B8 j# f3 J% L$ X: X
- {
) ?) g5 w( Q) w - /* Enable PWR and BKP clocks */ //使能APB1外设PWR and BKP 的时钟
( e* d0 w, }1 y: y, N2 v. o/ C D - /*打开电源和后备时钟*/1 m4 m1 R) k, e
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);8 o, U$ C) d. p/ N* t5 ~9 q+ {
: a6 P' U' B/ Q4 \; M! W- /* Allow access to BKP Domain*/ //允许RTC 和后备区域寄存器的访问7 m: Q6 K: h7 J) y) K0 [4 w
- PWR_BackupAccessCmd(ENABLE);
; w9 V" r @ \' |$ k% @, C2 u3 L8 a - 2 g! @0 ]' |$ g7 `
- /* Reset Backup Domain*/ //将外设BKP的全部 寄存器重设为缺省值
, x' h, k3 v9 j6 x/ h - BKP_DeInit();: G( O8 V! \& m
- # K2 ?* M: D2 l
- /* Enable LSE */ //设置(打开)外部低速时钟$ Z" _. X- G7 s+ J& a3 x
- RCC_LSEConfig(RCC_LSE_ON);
$ _& Q% u( t' F1 ?
8 {! b6 z+ b, _6 Z5 a6 f# y- /* Wait till LSE is ready */ //等待外部低速时钟准备好; D1 h4 E+ @' B
- while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);+ v$ O- w* x0 V, Y
( O9 h( {" V$ {& S+ Y7 S- /* Select LSE as RTC Clock Source */ //设置LSE为RTC时钟
2 k, G7 j' F# z: i3 ]% o - RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);/ i0 q4 V, Q( h7 F/ D$ ]" C
- ; _0 I) O7 t. q5 T$ {; O; S
- /* Enable RTC Clock */ //使能RT时钟/ I; K! g1 B1 Q/ c! x
- RCC_RTCCLKCmd(ENABLE);- |- j3 w4 S# a _& T
% \8 j4 \3 y% A4 g* M- //开始设置RTC,下面同步原因是:有两个时钟3 `8 Q i* ]. s6 u4 I
- /* Wait for RTC registers synchronization *///等待RTC寄存器(RTC_CNT,RTC_ALR and RTC_PRL)与RTC的APB时钟同步
7 t2 Q' t1 O z - RTC_WaitForSynchro();4 x8 P4 x& j% Q" b
7 N( o4 z* G6 d2 S- /* Wait untill last write operation on RTC register has finised *///等待最近一次对RTC的写操作完成
! e% z p& O: X" [ - RTC_WaitForLastTask();
* }" a( _) _, P, F! B; L+ L' A
# i+ f) r6 F8 K- /* Enable the RTC Second interrup */ //使能RTC的秒中断( l' b. R' h4 X2 W6 k2 x3 z) i
- RTC_ITConfig(RTC_IT_SEC,ENABLE);
1 i* ]+ Z" z4 Z) G: Y0 V' E
3 t e5 U8 L p8 ]$ V% e9 @( `- /* Wait untill last write operation on RTC register has finised */7 L% W6 t; { x/ x K7 Q2 m
- //等待最近一次对RTC的写操作完成) [5 c* d' {- r0 ]* H6 \! Z$ u
- RTC_WaitForLastTask();
% p9 N8 s9 e! M% m V/ A; S3 a
' P3 K2 O: f+ A- //分频值为32767+1=32768
( Y9 l# D0 ?" d5 H+ g; z - //计数频率=(32.768khz/32768)= 1hz! N) X) B9 n. P9 N" _5 V
- /* Set RTC prescaler : set RTC period to 1 sec*/ //设置RTC预分频的值
/ Z% z( [$ J+ n0 r W - RTC_SetPrescaler(32767);
+ O) w/ U: b0 H5 y - 9 \$ u& w: C0 l* m# l6 F
- /* Wait untill last write operation on RTC register has finised */+ r2 Q$ ~- {4 v) P/ t
- //等待最近一次对RTC的写操作完成
+ L$ V6 w( ^ D: Q; P ? - RTC_WaitForLastTask();7 g0 v6 U7 n2 D" q8 _$ H7 S; ]
- % R6 W" r% V" V5 p% G0 G X
- //设置当前的时间值
* e/ L9 k1 x; e4 J+ Y( f3 y* x% v4 o, y - /*2014.4.5 10:20:44 |9 }# S! {- t5 b9 s" |
- *t = 4+20*60+10*60*60 + 5*24*60*60+
$ x H; @3 W: h! L7 x2 p - *$ a6 o, G+ a4 `. | |# i/ w% i
- */
- S- H( _6 B3 Z/ Z) Z" k2 F - RTC_SetCounter((u32)t);0 H2 p! p3 g. x' k& n* ], V
- RTC_WaitForLastTask();
7 A7 }0 O8 z: k5 _5 K6 H; U - }
复制代码
6 |3 l" y9 p2 n* P |