STM32 RTC时钟日历实验

RTC概述

实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变。
系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问:
● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。

配置步骤

配置前需查看是否第一次配置(BKP_DR1寄存器数据是否为先前设置的值)

  1. 使能时钟
    配置参数存在BKP寄存器中 由PWR管理供电
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
  1. 使能BKP访问并初始化
	PWR_BackupAccessCmd(ENABLE); 
	BKP_DeInit();

将BKP设置为缺省值
RTC_PRL、 RTC_ALR、 RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位

  1. 使能LSI时钟
    40KHz好计算
	RCC_LSICmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET && Flag<255)
	{
		Flag++;
		delay_ms(10);
	}
	if(Flag == 255) return 1;

使能后还要等待晶振稳定 如果超时则返回错误代码1
之前的学习中不用使能HSE时钟是因为启动文件中已经将HSE选为系统时钟并使能,而当时钟被选为系统时钟时不能被关闭

  1. 选择RTC时钟源并使能RTC时钟
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); 
	RCC_RTCCLKCmd(ENABLE);
  1. 配置RTC时钟参数
    先进入配置模式等待同步完成
    时钟公式Time=(PRL+1)/RTCCLK
	RTC_EnterConfigMode();
	RTC_WaitForSynchro();
	RTC_WaitForLastTask();
	RTC_SetPrescaler(40000-1);
	RTC_WaitForLastTask();
	RTC_ITConfig(RTC_IT_SEC,ENABLE);
	RTC_WaitForLastTask();
	RTC_SetTime(2020,8,16,21,41,55);
	RTC_WaitForLastTask();
	RTC_ExitConfigMode();

每次对寄存器操作完成后都要等待写入完成

  1. 初始化RTC定时器秒中断
	NVIC_InitTypeDef NVIC_RTC_Sec_Init;
	NVIC_RTC_Sec_Init.NVIC_IRQChannel=RTC_IRQn;
	NVIC_RTC_Sec_Init.NVIC_IRQChannelCmd=ENABLE;
	NVIC_RTC_Sec_Init.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_RTC_Sec_Init.NVIC_IRQChannelSubPriority=2;
	NVIC_Init(&NVIC_RTC_Sec_Init);

之后获取时间且向BKP_DR1寄存器写入标识码即可

  1. 非第一次启动
    使能秒中断并初始化中断即可
	RTC_WaitForSynchro();
	RTC_WaitForLastTask();
	RTC_EnterConfigMode();
	RTC_ITConfig(RTC_IT_SEC,ENABLE);
	RTC_ExitConfigMode();
	RTC_NVIC_INIT();
	RTC_GetTime();
  1. 中断服务函数
void RTC_IRQHandler()
{
	if(RTC_GetITStatus(RTC_IT_SEC))
	{
		RTC_GetTime();
		RTC_ClearITPendingBit(RTC_IT_SEC);
	}	
}

写入获取时间

写入时间

void RTC_SetTime(unsigned short year,unsigned char mon,unsigned char day,unsigned char hour,unsigned char min,unsigned char sec)
{
	unsigned int count=0,num;
	for(num=1970;num<year;num++)
	{
		if(IS_Leap_Year(num)) count+=31622400;           //366*24*60*60
		else count+=31536000;                                    //365*24*60*60
	}                                        
	for(num=0;num<(mon-1);num++)
	{
		count+=(unsigned int)month[num]*86400;              //24*60*60
	}                                        
	if(IS_Leap_Year(year) && mon>2) count+=86400;      
	count+=(unsigned int)(day-1)*86400;                  
	count+=(unsigned int)hour*3600;                  //60*60
	count+=(unsigned int)min*60;
	count+=sec;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);   
	PWR_BackupAccessCmd(ENABLE);
	RTC_EnterConfigMode();
	RTC_WaitForSynchro();
	RTC_WaitForLastTask();
	RTC_SetCounter(count);
	RTC_WaitForLastTask();
	RTC_ExitConfigMode();
}

获取时间

void RTC_GetTime()
{
	unsigned int count=RTC_GetCounter(),time;
	unsigned short TimeCount;

	time=count/86400;                   //60*60*24  
	for(TimeCount=1970;time>=365;TimeCount++)
	{
		if(IS_Leap_Year(TimeCount))
		{
			if(time>=366)
			{
				time-=366;
			}
		}
		else
		{
			time-=365;
		}
	}
	Time.year=TimeCount;

	for(TimeCount=1;time>=month[TimeCount];TimeCount++)
	{
		time-=month[TimeCount];
	}
	Time.mon=TimeCount;
	Time.day=time; 
	
	time=count%86400;          
	Time.hour=time/3600;
	time%=3600;                 
	Time.min=time/60;
	Time.sec=time%60;
	get_week();
}

获取星期

void get_week()
{
	Time.week = (Time.day + 1+ 2*Time.mon+3*(Time.mon+1)/5+Time.year+Time.year/4-Time.year/100+Time.year/400)%7;
}
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值