上一篇:STM32-(26):RCC内部结构与原理分析 | 下一篇:STM32-(28):ADC模数转换(理论分析) |
---|
实时时钟的缩写是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控制寄存器设置了相应允许位则比较匹配时将产生一个闹钟中断。
分析
RTCCLK 外部低速时钟信号进来,先进入 RTC_DIV(分频器),RTC_PRL是装载器,然后得到一个 TR_CLK的信号,这个信号严格来说是 1s来一次,产生精确的秒信号,秒信号一路可以通过 RTC_Second,产生一个 RTC_CR 的标志位 SECF,当 SECIE 打开了(这个相当于一个开关,这个信号灯额中断允许位,表示允许秒信号输入),(SECF和SECIE是与的关系)就会产生一个中断;秒信号也可以输入到后面的 RTC_CNT计数器,这个计数器可以进行32位(2的32次方)的编程控制,当计数器寄存器的值达到设定的值就会产生 RTC_Overflow 信号,后面的 OWIE 如果打开,也会产生中断;如果设定的 RTC_ALR的值(报警),当计数器寄存器的值等于报警相关寄存器设定值,就会产生闹钟信号 RTC_Alarm,同时 ALRIE 打开,就会产生中断。这三种信号产生的中断就会进入下方的 NVIC INTERRUPT CONTRCLLER(中断控制器),相当于强制让CPU处理这个中断信号。 RTC_Alarm 和 WKUP_pin是或的关系,有任何一个信号,就会产生中断或者 进入 EXIT FROM ,就是从 常置状态跳出 ,唤醒CPU的意思;上方一整个灰色阴影区域表示这块区域的工作不是由VCC电源直接供电的(当然也可以由VCC供电),当VCC电源无效的时候或者说CPU没有工作的时候,是由后备电池供电的,这个区域称为“后备区”,系统在断电复位的情况下,不会影响后备区。比如手机电脑关机开机后,时间显示总是正确的。
主要特性
**可编程的预分频系数:**分频系数最髙为220
32位的可编程计数器,可用于较长命间段的测量。
2个单独的时钟,用于APB1接口的PCLK1和RTC时钟(此时的RTC时钟必须小于PCLK1时钟的四分之一以上)
2种独立的复位类型:
APB1接口由系统复位
RTC只能由后备域复位
3个专门的可屏蔽中断 :
闹钟中断,用来产生一个软件可编程的闹钟中断。
秒中断,用来产生一个可编程的周期性中断信号
溢出中断,检测内部可编程计数器溢出并回转为0的状态。
RTC 的一些设置是保存在后备域中的: RTC_PRL,RTC_ALR,RTC_CNT 和 RTC_DIV 寄存器。
这些寄存器器仅能通过备份域复位信号复位,不受系统复位或电源复位的影响。
备份域复位
当以下事件中之一发生时,产生备份区域复位。
- 软件复位,备份区域复位可由设置备份区域控制寄存器 RCC _ BDCR 中的 BDRST 位产生。
- 在 VDD 和 VBAT 两者掉电的前提下, VDD 或 VBAT 上电将引发备份区域复位。
对相关寄存器操作流程
要对 RTC_PRL . RTC_CNT . RTC_ALR 寄存器进行写操作, RTC 必须进入配置模式。通过对 RTC_CRL寄存器中的 CNF 位置位使 RTC 进入配置模式。另外,对 RTC 的任何寄存器的写操作都必须在前一次写操作结束以后进行。要使用软件来查询当前的状态,同可通过查询 RTC_CR 寄存器中的 RTOFF状态位来判断 RTC 寄存器是否处于更新中,仅当 RTOFF 状态位是“1”时,RTC 寄存器可以写入新的值。
配置过程:
- 查询 RTOFF 位,直到 RTOFF 的值变为“ 1 ”
- 置 CNF 值 为1 , 进入配置模式
- 对一个或多个 RTC 寄存器进行写操作
- 清除 CNF 标志位,退出配置模式
- 查询 RTOFF,直至RTOFF位变为“1”以确认写操作已经完成。
仅当 CNF 紅志位被清除时.写操作才能进行,这个过程至少需要3个 RTCCLK 周期
RTC相关寄存器
RTC_CRH
OWIE:允许溢出中断位
0:屏蔽(不允许)溢出中断
1:允许溢出中断
ALRIE:允许闹钟中断
0:屏蔽(不允许)闹钟中断
1:允许闹钟中断
SECIE:允许秒中断
0:屏蔽(不允许)秒中断
1:允许秒中断
RTC_CRL
RTOFF: RTC操作关闭
RTC模块利用这位来指示对其寄存器进行的最后一次操作的状态,指示操作是否完成。若此位为0,则无法对任何的RTC寄存器进行写操作。此位为只读位。
0:上一次对RTC寄存器的写操作仍在进行;
1:上一次对RTC寄存器的写操作已经完成。
CNF:配置标志
此位必须由软件置1以进入配置模式,从而允许向RTC_CNT、RTC_ALR或RTC_PRL寄存器写入数据。只有当此位在被置1后,并重新由软件清0后,才会执行写操作。
0:退出配置模式(开始更新RTC寄存器);
1:进入配置模式。
RSF:寄存器同步标志
每当RTC_CNT寄存器和RTC_DIV寄存器由软件刷新或清0时,此位由硬件置1。在APB1复位后,或APB1时钟停止后,此位必须由软件清0。要进行任何的读操作之前,用户程序必须等待这位被硬件置1,以确保RTC_CNT、RTC_ALR或RTC_PRL已经被同步。
0:寄存器尚未被同步;
1:寄存器已经被同步。
OWF:溢出标志
当32位可编程计数器溢出时,此位由硬件置1。如果RTC_CRH寄存器中OWIE=1,则产生中断。此位只能由软件清0。对此位写1是无效的。
0:无溢出;
1:32位可编程计数器溢出。
ALRF:闹钟标志
当32位可编程计数器达到RTC_ALR寄存器所设置的门限值,此位由硬件置1。如果RTC_CRH寄存器中ALRIE=1,则产生中断。此位只能由软件清0。对此位写1是无效的。
0:无闹钟;
1:有闹钟。
SECF:秒标志
当32位可编程预分频器溢出时,此位由硬件置1,RTC计数器递增。因此,此标志为分辨率可编程的RTC计数器提供一个周期性的信号(通常为1秒)。如果RTC_CRH寄存器中SECIE=1,则产生中断。此位只能由软件清除。对此位写“1”是无效的。
0:秒标志条件不成立;
1:秒标志条件成立。
RTC 计数器寄存器 (RTC_CNTH / RTC_CNTL)
RTC核有一个32位可编程的计数器,可通过两个16位的寄存器访问。计数器以预分频器产生的TR_CLK时间基准为参考进行计数。RTC_CNT寄存器用来存放计数器的计数值。他们被RTC_CR上的位RTOFF写保护,并且如果RTOFF值是1的话,允许写操作。在高或低寄存器(RTC_CNTH或RTC_CNTL)上的写操作,能够直接装载到相应的可编程计数器,并且重新装载RTC预分频器。当进行读操作时,直接返回计数器内的计数值(系统时间)。
RTC 闹钟寄存器(RTC_ALRH/RTC_ALRL )
当可编程计数器的值与RTC_ALR中的32位值相等时,即触发一个闹钟事件,并且产生RTC闹钟中断。此寄存器被RTC_CR寄存器里的RTOFF位写保护,如果RTOFF值是1时,允许写操作。
相关库函数
代码块
main.c
/*Includes----------------------------------*/
#include"stm32f10x_lib.h" //包含所用的头文件
#include<stdio.h>
//----------------外部函数的声明------------------------------
extern void SMG_Init(void);
extern void SMG_Display(u32 data,u8 dot); //数码管函数的声明(包含SPI函数的声明)
extern void RTC_Configuration(void);
//---------------------函数的声明---------------------------
void Delay_Ms(u16 time);
void RCC_Configuration(void);
void NVIC_Configuration(void);
extern vu8 Count;
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
#ifdef DEBUG
debug();
#endif
RCC_Configuration();
RTC_Configuration();
SMG_Init();
NVIC_Configuration();
while(1)
{
SMG_Display(Count,3);
}
}
/*******************************************************************************
* Function Name : Delay_Ms
* Description : delay 1 ms.
* Input : time (ms)
* Output : None
* Return : None
*******************************************************************************/
void Delay_Ms(u16 time) //延时函数
{
u16 i,j;
for(i=0;i<time;i++)
for(j=10000;j>0;j--);
}
/*******************************************************************************
* Function Name : RCC_Configuration
* Description : Configures the different system clocks.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void RCC_Configuration(void)
{
//-----------使用外部RC晶振-----------------
RCC_DeInit(); //初始化为缺省值状态
RCC_HSEConfig(RCC_HSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource()!=0x08);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
//Configure one bit for preemption priority
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQChannel; //设置RTC中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置先优先级为 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置亚优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_Init(&NVIC_InitStructure); //初始化
}
RTC.c
/********************************************************************
* 文件 :RTC.c
* 描述 : 实时时钟RTC模块的配置
********************************************************************/
#include"stm32f10x_lib.h"
/*************************************************************************************
**名称 ;void RTC_Configuration(void)
**功能 ;RTC实时时钟的配置
**入口参数 ;无
**出口参数 ;无
*************************************************************************************/
void RTC_Configuration(void)
{
/* Enable PWR and BKP clocks */ //使能APB1外设PWR and BKP 的时钟 (打开电源与后备电源)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
/* Allow access to BKP Domain*/ //允许RTC 和后备寄存器的访问
PWR_BackupAccessCmd(ENABLE);
/* Reset Backup Domain*/ //将外设BKP的全部 寄存器重设为缺省值
BKP_DeInit();
/* Enable LSE */ //设置外部低速时钟
RCC_LSEConfig(RCC_LSE_ON);
/* Wait till LSE is ready */ //等待外部低速时钟准备好
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
/* Select LSE as RTC Clock Source */ //设置LSE为RTC时钟
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable RTC Clock */ //使能RT时钟
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC registers synchronization *///等待RTC寄存器(RTC_CNT,RTC_ALR and RTC_PRL)与RTC的APB时钟同步
RTC_WaitForSynchro();
/* Wait untill last write operation on RTC register has finised *///等待最近一次对RTC的写操作完成
RTC_WaitForLastTask();
/* Enable the RTC Second interrup */ //使能RTC的秒中断
RTC_ITConfig(RTC_IT_SEC,ENABLE);
/* Wait untill last write operation on RTC register has finised *///等待最近一次对RTC的写操作完成
RTC_WaitForLastTask();
/* Set RTC prescaler : set RTC period to 1 sec*/ //设置RTC预分频的值 为32767,则计数频率 = (32.768 KHz)/(32767+1) = 1Hz(~1s)
RTC_SetPrescaler(32767);
/* Wait untill last write operation on RTC register has finised *///等待最近一次对RTC的写操作完成
RTC_WaitForLastTask();
}
上一篇:STM32-(26):RCC内部结构与原理分析 | 下一篇:STM32-(28):ADC模数转换(理论分析) |
---|