您的位置:首页 > 文旅 > 美景 > STM32学习和实践笔记(38):RTC实时时钟实验

STM32学习和实践笔记(38):RTC实时时钟实验

2024/12/23 8:07:02 来源:https://blog.csdn.net/qq_37191547/article/details/139928079  浏览:    关键词:STM32学习和实践笔记(38):RTC实时时钟实验

1.STM32F1 RTC介绍

 STM32 的实时时钟( RTC)是一个独立的定时器。

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

RTC模块和时钟配置是在后备区域,无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要保证后备区域供电正常,RTC便不会停止工作,所以通常会在后备区域供电端加一个纽扣电池,即使主电源停止供电,后备电源也会启动供电,从而保证RTC时钟不停的运行,只有当主电源和后备纽扣电池都没有电的时,RTC才停止工作。 

从 RTC 的定时器特性来说,它是一个 32 位的计数器,只能向上计数。它的时钟来源有三种,分别为高速外部时钟的 128 分频( HSE/128)、 低速内部时钟 LSI 以及低速外部时钟 LSE。

但一般都是使用低速外部时钟 LSE作为时钟来源。因为只有这样主电源掉电RTC才不会停止。

LSE 通常都是32.768KHZ ,因为2的15次方刚好是32768,这样方便对这个频率进行分频。例如,2的15次方,二进制向左移一位,变成2的14次方,就是一次分频,即32768/2=16384.

2. RTC结构框图

  STM32F1 RTC拥有这么多功能,是由RTC内部结构决定。要更好的理解STM32F1的RTC,就需要了解它内部的结构。如图32.1.1所示:(大家也可以查看《STM32F10x中文参考手册》-16实时时钟(RTC)章节内容

  系统复位后默认禁止访问后备寄存器和 RTC,防止对后备区域(BKP)的意外写操作。执行以下操作使能对后备寄存器和 RTC 的访问

(1) 设置 RCC_APB1ENR 寄存器的 PWRENBKPEN 位来使能电源和后备接口时钟

(2) 设置电源控制寄存器(PWR_CR)的 DBP 位使能对后备寄存器和 RTC 的访问

  设置后备寄存器为可访问后,在第一次通过 APB1 接口访问 RTC 时, 因为时钟频率的差异,所以必须等待 APB1 与 RTC 外设同步,确保被读取出来的 RTC 寄存器值是正确的。若在同步之后,一直没有关闭 APB1 的 RTC 外设接口,就不需要再次同步了

  如果内核要对 RTC寄存器进行任何的写操作,在内核发出写指令后, RTC模块在 3个RTC CLK 时钟之后,才开始正式的写 RTC 寄存器操作

由于 RTC CLK 的频率比内核主频低得多,所以每次操作后必须要检查 RTC关闭操作标志位 RTOFF,当这个标志被置 1 时,写操作才正式完成。

3.STM32F1 RTC配置步骤

  RTC相关库函数在stm32f10x_rtc.c和stm32f10x_rtc.h文件中)具体配置步骤如下:

(1)使能电源时钟和后备域时钟,开启RTC后备寄存器写访问

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);

PWR_BackupAccessCmd(ENABLE);//打开后备寄存器访问

(2)复位备份区域,开启外部低速振荡器

BKP_DeInit();

RCC_LSEConfig(RCC_LSE_ON);

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

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

RCC_RTCCLKCmd(ENABLE);

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

RTC_EnterConfigMode();// 允许配置

RTC_ExitConfigMode();

void RTC_SetPrescaler(uint32_t PrescalerValue);

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);

RTC_ITConfig(RTC_IT_SEC, ENABLE);

void RTC_SetCounter(uint32_t CounterValue);

(5)更新配置,设置 RTC 中断分组

RTC_ExitConfigMode();//退出配置模式,更新配置

void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);

BKP_WriteBackupRegister(BKP_DR1, 0XA0A0);

uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);

(6)编写RTC中断服务函数

RTC_IRQHandler

FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);

RTC_ClearITPendingBit(RTC_IT_SEC);

3.硬件电路

本实验使用到硬件资源如下

1)D1指示灯

2)串口1

3)RTC

  RTC属于STM32F1芯片内部的资源,只要通过软件配置好即可使用。

D1指示灯用来提示系统运行状态。串口1将读取的RTC时间日期信息打印出来。

这里需要注意RTC 不能断电,否则时间数据将会丢失,如果想让时间在断电后还可以继续走,那么必须确保开发板上的纽扣电池有电。      

4.编写RTC控制程序

  本实验所要实现的功能是:设置RTC时间日期初值,在RTC秒中断内使用串口打印出RTC日期和时间,D1指示灯闪烁提示系统运行。

程序框架如下:

(1)初始化RTC,设置RTC时间日期初值

(2)开启RTC的秒中断,编写RTC中断函数,

(3)在RTC中断内更新时间并打印输出

(4)编写主函数

main.c

#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "usart.h"
#include "rtc.h"int main()
{u8 i=0;SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组LED_Init();USART1_Init(9600);RTC_Init();while(1){i++;if(i%20 ==0){led1=!led1;//LED1闪,用来指示主程序循环是否运行delay_ms(300);}}}

         rtc.c

#include "rtc.h"
#include "SysTick.h"
#include "system.h"
#include "usart.h"_calendar calendar;void RTC_NVIC_Confing()//RTC中断优先级配置函数
{NVIC_InitTypeDef NVIC_InitStructure;//设置中断优先级,使能中断通道NVIC_InitStructure.NVIC_IRQChannel=	RTC_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}void RTC_Get()
{u32 timedata =0;timedata=RTC_GetCounter();calendar.hour=timedata/3600;calendar.min=(timedata%3600)/60;calendar.sec=timedata%60;
}//初回1:初始化失败
//初回0:初始化成功
u8 RTC_Init() //有返回值是因为需要判断初始化是否成功
{u8 temp =0;RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能电源时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//使能后备域时钟PWR_BackupAccessCmd(ENABLE);//打开后备寄存器访问if(BKP_ReadBackupRegister(BKP_DR1)!=0xA0A0)//后备寄存器有42个,都可以用来存放后备数据,这里选用第1个{BKP_DeInit();//复位备份区域,RCC_LSEConfig(RCC_LSE_ON);//开启外部低速振荡器while((RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET)&&(temp<250)) //等待外部低速振荡ready{temp++;delay_ms(10);}if(temp>=250){return 1;}RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//配置RTCC的时钟源为LSERCC_RTCCLKCmd(ENABLE);RTC_WaitForLastTask();//等待写操作完成RTC_WaitForSynchro();//等待时钟同步RTC_ITConfig(RTC_IT_SEC,ENABLE);//配置中断类型为秒中断并开启RTC_WaitForLastTask();//等待写操作完成		RTC_EnterConfigMode();// 允许配置RTC_SetPrescaler(32767);RTC_WaitForLastTask();//等待写操作完成		RTC_SetCounter(0xf73f);//初始化时间初值为17:34:55,计算方法是全部计算成秒,即17*3600+34*60+55=0xf73fRTC_ExitConfigMode();			BKP_WriteBackupRegister(BKP_DR1, 0xA0A0);//这样第二次开机时就不会进入上面的初始化了}else //第二次开机时走这里{RTC_WaitForSynchro();//等待时钟同步RTC_ITConfig(RTC_IT_SEC,ENABLE);//配置中断类型为秒中断并开启		RTC_WaitForLastTask();//等待写操作完成	}RTC_NVIC_Confing();RTC_Get();return 0;}void RTC_IRQHandler(void)
{if(RTC_GetITStatus(RTC_IT_SEC)!=RESET)//判断秒中断是否产生,如产生执行下面的语句{RTC_Get();printf("RTC Time:%d:%d:%d\r\n",calendar.hour,calendar.min,calendar.sec);}RTC_ClearITPendingBit(RTC_IT_SEC);//清除中断状态标志}

程序烧写到开发板,实验结果如下,实验是成功的。

                      

                  

         

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com