STM32-----RTC

本文详细介绍了STM32的RTC模块工作原理,包括如何配置时钟、取消备份区域写保护、设置时间和日期,以及备份操作和中断服务函数的实现。
摘要由CSDN通过智能技术生成

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

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

 

备份寄存器(BKP)

        备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域 里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或 电源复位时,他们也不会被复位。 此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。 复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操 作。执行以下操作可以使能对备份寄存器和RTC的访问。

        ● 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟

        ● 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

二、RTC配置步骤

(1) 使能电源时钟和备份区域时钟

        我们要访问 RTC 和备份区域就必须先使能电源时钟和备份区域时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

(2)取消备份区写保护

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

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

PWR_BackupAccessCmd(ENABLE); //使能 允许RTC和后备寄存器访问

(3) 复位备份区域。(清空备份寄存器)

        当TAMPER引脚上的信号从0变成1或者从1变成0(取决于备份控制寄存器BKP_CR的TPAL位), 会产生一个侵入检测事件。侵入检测事件将所有数据备份寄存器内容清除。 然而为了避免丢失侵入事件,侵入检测信号是边沿检测的信号与侵入检测允许位的逻辑与,从 而在侵入检测引脚被允许前发生的侵入事件也可以被检测到。

BKP_DeInit();//复位备份区域

(4)开启外部低速振荡器

RCC_LSEConfig(RCC_LSE_ON);

(5)等待LSE准备就绪

while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  {}

(6) 选择 RTC 时钟,并使能

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择 LSE 作为 RTC 时钟(RCC_RTCCLKSource_LSI 和 RCC_RTCCLKSource_HSE_Div128)
RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟

(7)设置 RTC 的分频,以及配置 RTC 时钟

        在开启了 RTC 时钟之后,我们要做的是设置 RTC 时钟的分频数,通过 RTC_PRLH 和RTC_PRLL 来设置,然后等待 RTC 寄存器操作完成,并同步之后,设置秒钟中断。然后设置 RTC 的允许配置位(RTC_CRH 的 CNF 位),设置时间(其实就是设置RTC_CNTH 和 RTC_CNTL两个寄存器)。
        对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器.

 a.进行配置要先等待

         查阅固件函数库用户手册可知:对于RTC的配置(设置分频等)基本需要在调用函数前先调用RTC_WaitForLastTask(),等待标志位RTOFF被设置。如下RTC_SetPrescaler函数

  b.设置秒中断允许

RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成

 c.配置之前要先允许配置

RTC_EnterConfigMode();/// 允许配置

d.设置分屏

RTC_SetPrescaler(32768 - 1);					//设置RTC预分频器,预分频后的计数频率为1Hz
RTC_WaitForLastTask();							//等待上一次操作完成

 e.退出配置模式

RTC_ExitConfigMode(); //退出配置模式 
void RTC_Configuration(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问  
	
    NVIC_InitTypeDef NVIC_InitStructure={0};

      /* Enable the RTC Interrupt */
      NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);


    
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
	RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟  
	RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
	RTC_WaitForSynchro();		//等待RTC寄存器同步  
	RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断
	RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
	RTC_EnterConfigMode();/// 允许配置	
	RTC_SetPrescaler(32767); //设置RTC预分频的值
	RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
	RTC_Set(1972,1,2,1,1,1);  //设置时间	
	RTC_ExitConfigMode(); //退出配置模式  

}

三、设置时间(起始时间)

        设置时间实际上就是设置 RTC 的计数值,时间与计数值之间是需要换算的。库函数中设置 RTC 计数值的方法是:

        mktime()函数头文件是time.h

        struct tm Set_time={0,8,16,8,4-1,2024-1900};

//void RTC_SetCounter(uint32_t CounterValue)//最后在配置完成之后

//	RTC_SetCounter(1712563329); 
  RTC_SetCounter(mktime(&Set_time)); //根据结构体转成s数
//设置时间
void Time_Adjust(void)
{
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
  /* Change the current time */
//	RTC_SetCounter(1712563329); 
  RTC_SetCounter(mktime(&Set_time)); //根据结构体转成s数
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
}

四、备份操作

      在退出配置模式更新配置之后我们在备份区域 BKP_DR1 中写入 0X5050 代表我们已经初始化过时钟了,下次开机(或复位)的时候,先读取 BKP_DR1 的值,然后判断是否是 0X5050 来决定是不是要配置。接着我们配置 RTC 的秒钟中断,并进行分组。
往备份区域写用户数据的函数是

        这个函数的第一个参数就是寄存器的标号了,这个是通过宏定义定义的。 比如我们要往
BKP_DR1 写入 0x5050,方法是:

void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);

同时,有写便有读,读取备份区域指定寄存器的用户数据的函数是

uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);

五、 编写中断服务函数

uint8_t Second_Flag=0;
void RTC_IRQHandler(void)
{
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  {
    /* Clear the RTC Second interrupt */
    RTC_ClearITPendingBit(RTC_IT_SEC);

    Second_Flag = 1;

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();  
  }
}

 

 

 

 

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

膽小

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值