stm32-RTC实时时钟原理及代码解析

目录

一、介绍

1.简介

二、RTC原理和代码详解:

第一步设置RTC.

1前提:

2时钟

第二步APB1接口

1.预分频模块

2可编程计数器模块

第三步:主函数


一、介绍

1.简介

        实时时钟是一个独立的定时器,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

        在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。

二、RTC原理和代码详解:

框图代码分析:

stm32-RTC实时时钟原理及代码解析_第1张图片

CPU和RTC独立。我们要通过APB1操纵RTC。

第一步设置RTC.

1前提:

        后备域前期配置

        RTC可提供时钟日历的功能,我们每次复位如果它都重新计时显然不符合实际需要。所以stm32芯片将它和cpu独立。内部加上一个存储器外部附上一个独立电源。使其成为一个真正的计时工具。

        所以当我们使用RTC时我们需要先打开独立供电区(PWR)和后备域(存储器位于后备域)(BKP)

        然后设置后备域允许访问。

        让后备域复位。

        数据手册相关叙述:

        系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操
作。执行以下操作将使能对后备寄存器和RTC的访问:
        ● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
        ● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。

        TC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问  
BKP_DeInit();	//复位备份区域 (让其有个初始值)	

2时钟

stm32-RTC实时时钟原理及代码解析_第2张图片

        PCLK1:时钟来源APB1最大36MHz。HSE时钟除以128

         RTCCLK:LSI振荡器时钟(40kHz)或LSE振荡器时钟(32.768kHz)驱动

stm32-RTC实时时钟原理及代码解析_第3张图片

代码1:

        VDD掉电的情况下,需要尽量保持时钟来源不会会受到影响,所以一般选择LSE振荡器时钟。

        先设置外部低速时钟。

        设置完毕,我们要确保LSE振荡器时钟正常。通过while循环检查相关标志位。

       选择LSE,使能。

RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振(LSE)
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)	//检查指定的RCC标志位设置否,等待低速晶振就绪
{
    temp++;
	delay_ms(10);
}
if(temp>=250)return 1;//初始化时钟失败,晶振有问题	  
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时//(RCC_RTCCLKSource_LSI 和 RCC_RTCCLKSource_HSE_Div128)  
RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟 

第二步APB1接口

        RTC设置完后,我们终于可以通过过APB1接口控制RTC了

        APB1和RTC时钟同步才能数据交换,如果最近一次写操作持续等待它完成。

        同时数据手册也规定了配置寄存器步骤

        1. 查询RTOFF位,直到RTOFF的值变为’1’
        2. 置CNF值为1,进入配置模式
        3. 对一个或多个RTC寄存器进行写操作
        4. 清除CNF标志位,退出配置模式
        5. 查询RTOFF,直至RTOFF位变为’1’以确认写操作已经完成

RTC_WaitForSynchro();		//等待RTC寄存器同步 
RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成 

1.预分频模块

        它可编程产生最长为1秒的RTC时间基准TR_CLK.

        RTC的预分频模块包含了一个20位的可编程分频器(RTC预分频器)。如果在RTC_CR寄存器中设置了相应的允许位,则在每个实时时钟(RTC)TR_CLK周期中RTC产生一个中断(秒中断)

        从图上得,TR_CLK这条线产生了一个中断

        于是乎,我们通过APB1写第一条语句使能这个中断,并等待它写完

        预分频器我们也设置一下(1s)这是第二个语句同样等待它写完。

        同理再写个时间初始值。

stm32-RTC实时时钟原理及代码解析_第4张图片

代码:

RTC_EnterConfigMode();/// 允许配置	
RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断,写操作,断电不保存
RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
RTC_SetPrescaler(32767); //设置RTC预分频的值
RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
RTC_Set(2021,1,14,17,42,55);  //这个函数得自己写
BKP_WriteBackupRegister(BKP_DR1, 0X5050);
RTC_ExitConfigMode(); //退出配置模式  

        我们需要想一个问题,这样设置断不断电不久没区别了。所以我们要通过一些代码让他重复进入有区别。

 代码:

if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)
{


BKP_WriteBackupRegister(BKP_DR1, 0X5050);	
}

          根据手册得秒中断使能是不保存到独立存储器的,换而言之,我们需要重新配置秒中断。

代码:

else//系统继续计时
	{

		RTC_WaitForSynchro();	//等待最近一次对RTC寄存器的写操作完成
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
	}
RTC_NVIC_Config();
RCC_ClearFlag();//清除复位标志

        由于我们用到了中断我们自然需要配置NVIC ,以及中断函数

代码:

static void RTC_NVIC_Config(void)
{	
  NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		//RTC全局中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//先占优先级1位,从优先级3位
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	//先占优先级0位,从优先级4位
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能该通道中断
	NVIC_Init(&NVIC_InitStructure);		//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
void RTC_IRQHandler(void)
{		 
	if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
	{							
		RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);		//清闹钟中断  
		time_bz=1;//用个变量记录一下
  	} 				  								 
	    						 	   	 
}

2可编程计数器模块

        是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。

        我们前面设置的预分频模块产生的总时间累计在这

代码:

RTC_GetCounter();

第三步:主函数

主函数:

while(tim_bz==1)
{
    tim_bz=0;
    (u32)a=RTC_GetCounter();
    h=a/3600;
    min=(a%3600)/60;
    s=(a%60)/60;
    printf();
}

你可能感兴趣的:(stm32基础知识,stm32,实时音视频,单片机)