【STM32】RTC的初始化与基本使用(CT117E电路)

目录

RTC的初始化与基本使用

RTC的初始化

RTC的基本使用

参考文献


RTC的初始化与基本使用

STM32 的实时时钟(RTC)是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数 的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当 前的时间和日期。

RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式 唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC, 以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP) 写保护

RTC 的简化框图:

 RTC 由两个主要部分组成(参见图 18.1.1),第一部分(APB1 接口)用来和 APB1 总线相连。 此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总 线时钟驱动,用来与 APB1 总线连接。

另一部分(RTC 核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是 RTC 的 预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20 位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个 TR_CLK 周期中 RTC 产生一个中断(秒中断)。第二个模块是一个 32 位的可编程计数器,可被 初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记录 4294967296 秒, 约合 136 年左右,作为一般应用,这已经是足够了的。

RTC 还有一个闹钟寄存器 RTC_ALR,用于产生闹钟。系统时间按 TR_CLK 周期累加并与存储在 RTC_ALR 寄存器中的可编程时间相比较,如果 RTC_CR 控制寄存器中设置了相应允许 位,比较匹配时将产生一个闹钟中断。

RTC 内核完全独立于 RTC APB1 接口,而软件是通过 APB1 接口访问 RTC 的预分频值、计 数器值和闹钟值的。但是相关可读寄存器只在 RTC APB1 时钟进行重新同步的 RTC 时钟的上升 沿被更新,RTC 标志也是如此。这就意味着,如果 APB1 接口刚刚被开启之后,在第一次的内 部寄存器更新之前,从 APB1 上读取的 RTC 寄存器值可能被破坏了(通常读到 0)。因此,若 在读取 RTC 寄存器曾经被禁止的 RTC APB1 接口,软件首先必须等待 RTC_CRL 寄存器的 RSF 位(寄存器同步标志位,bit3)被硬件置 1。

RTC的初始化

void RTC_Init(u8 hh,u8 mm,u8 ss)
{
	//中断的初始化配置
	NVIC_InitTypeDef NVIC_InitStructure;//中断初始化结构体
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
	//RTC需要的时钟总线不是APB2下的,而是APB1
	//RCC_APB1Periph_BKP	备份寄存器
	//RCC_APB1Periph_PWR  电源
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//中断请求名称
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//配置通道是否开启(ENABLE:1为开启)
	NVIC_Init(&NVIC_InitStructure);//中断初始化
	
	//RTC时钟配置
	PWR_BackupAccessCmd(ENABLE);//PWR下的能源控制的功能函数->BKP->备份寄存器通电
	//								该函数功能:给备份寄存器通电
	BKP_DeInit();//BKP重置(等价于默认初始化)

	RCC_LSICmd(ENABLE);//使能LSI内部时钟
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);//等待LSI时钟使能完成

	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//RTC时钟--利用LSI时钟频率进行计数
	RCC_RTCCLKCmd(ENABLE);//对RTC时钟进行使能

	//中断进行配置
	RTC_ITConfig(RTC_IT_SEC,ENABLE);//中断配置函数--RTC_IT_SEC:秒中断
	RTC_WaitForLastTask();//等待上一次任务完成的应答
	
	RTC_WaitForSynchro();//RTC初始化系统配置
	RTC_WaitForLastTask();//等待上一次任务完成的应答
	
	RTC_SetPrescaler(40000-1);//时钟分频---对应的技术周期的影响
	RTC_WaitForLastTask();//等待上一次任务完成的应答
	
	RTC_SetCounter(hh*3600+mm*60+ss);//初始化RTC中的计数值
	rtctime_value = hh*3600+mm*60+ss;//这里的变量是程序当中的全局变量(此处未列出是变量定义)
	RTC_WaitForLastTask();//等待上一次任务完成的应答
}

我们要访问 RTC 和备份区域就必须先使能电源时钟和备份区域时钟。设置RCC_APB1ENR寄存器的PWREN和BKPEN位来使能电源和后备接口时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);

要向备份区域写入数据,就要先取消备份区域写保护(写保护在每次硬复位之后被使能), 否则是无法向备份区域写入数据的。我们需要用到向备份区域写入一个字节,来标记时钟已经 配置过了,这样避免每次复位之后重新配置时钟。取消备份区域写保护的库函数实现方法是:

PWR_BackupAccessCmd(ENABLE);

在取消备份区域写保护之后,我们可以先对这个区域复位,以清除前面的设置,当然这个 操作不要每次都执行,因为备份区域的复位将导致之前存在的数据丢失,所以要不要复位,要 看情况而定。然后我们使能外部低速振荡器,注意这里一般要先判断 RCC_BDCR 的 LSERDY 位来确定低速振荡器已经就绪了才开始下面的操作。 备份区域复位的函数是:

BKP_DeInit();//BKP重置(等价于默认初始化)

使能对应的是时钟:

根据上面的时钟可以看到,使能LSI内部时钟后,对RTCCLKRTC时钟配置对应的时钟源(由于是用LSI,所以配置时钟源为LSI),配置好RTXCCLK时钟的时钟源后对RTC时钟进行使能。

	RCC_LSICmd(ENABLE);//使能LSI内部时钟
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);//等待LSI时钟使能完成
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//RTC时钟--利用LSI时钟频率进行计数
	RCC_RTCCLKCmd(ENABLE);//对RTC时钟进行使能

RTC(Real Time Clock)是实时时钟的意思,它其实和TIM有点类似,也是利用计数的原理,选择RTC时钟源,再进行分频,到达计数的目的。

RTC的秒中断功能类似SysTick系统滴答的功能。RTC秒中断功能其实是每计数一次就中断一次。注意,秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。
————————————————
版权声明:本文为CSDN博主「蚂蚁经书」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lilp2896/article/details/98875436

这里要注意由于是编写的时间程序,所以说按照1s依次中断,故按照上图的LSI时钟源的频率40000hz,进行时间分频的时候设置40000,以达到1Hz频率的目的

读写寄存器前,要确定上一个操作已经结束:RTC_WaitForLastTask();既等待直到对RTC寄存器的最近一次写操作完成。

	//中断进行配置
	RTC_ITConfig(RTC_IT_SEC,ENABLE);//中断配置函数--RTC_IT_SEC:秒中断
	RTC_WaitForLastTask();//等待上一次任务完成的应答

等待直到RTC寄存器(RTC_CNT,RTC_ALR和RTC_PRL)与RTC APB时钟同步:

	RTC_WaitForSynchro();//RTC初始化系统配置
	RTC_WaitForLastTask();//等待上一次任务完成的应答

为RTC定时器设置初值(由于对RTC进行了基本的初始化后进行的操作都要经过APB1口,所以都要等待直到对RTC寄存器的最近一次写操作完成):

	RTC_SetCounter(hh*3600+mm*60+ss);//初始化RTC中的计数值
	rtctime_value = hh*3600+mm*60+ss;//这里的变量是程序当中的全局变量(此处未列出是变量定义)
	RTC_WaitForLastTask();//等待上一次任务完成的应答

RTC的基本使用

主要使用RTC_GetCounter函数和RTC_SetCounter函数

	rtctime_value=RTC_GetCounter();
    RTC_SetCounter(hh*3600+mm*60+ss);

 根据需要配置中断服务函数,例如时间显示程序的中断服务函数:

extern u8 nowtime[];
void RTC_IRQHandler(void)
{
	u32 counter;
	if(RTC_GetITStatus(RTC_IT_SEC)==1)//判断执行的是否是秒中断
	{	//个人理解,如果有多个中断操作时,可以用此方法来使不同中断区别执行
		RTC_ClearITPendingBit(RTC_IT_SEC);
		//清除秒中断标志位,好为下次中断做准备
		RTC_WaitForLastTask();
		counter=RTC_GetCounter();
		RTC_WaitForLastTask();
		if(counter==(23*3600+59*60*59))
		{
			RTC_SetCounter(0x00);
			RTC_WaitForLastTask();
		}
		nowtime[0]=counter/3600%24;
		nowtime[1]=counter%3600/60;
		nowtime[2]=counter%3600%60;
		USART2_COMUP();//其他的串口功能
	}
}

参考文献

[1] RTC_WaitForSynchro() https://blog.csdn.net/qinrenzhi/article/details/82558556

[2] STM32不完全手册_库函数版本_V3.1

[3] Stm32 中RTC秒中断的使用方法及例子 https://blog.csdn.net/lilp2896/article/details/98875436

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值