2018-12-STM32F103- RTC实时时钟学习

实时时钟(RTC)

概述
RTC(real-time clock),实时时钟是一个独立的时钟,RTC被使用时提供连续不断的技术,用这个功能可以提供时间或者日历服务。
可以计数到2的32次方
1.1RTC使用的时钟

2.1可以使用的中断
在这里插入图片描述
2.1第一个中断可以选择到什么时间产生中断RTC_IT_ALR
2.2第二个可以每秒产生一个中断RTC_IT_SEC
2.3第三个是数据溢出时的中断信号,计数到了2的32次方RTC_IT_OW:

@arg RTC_IT_ALR: Alarm interrupt
@arg RTC_IT_SEC: Second interrupt
@arg RTC_IT_OW: Overflow interrupt

2.4RTC的中断配置函数

3.功能框图

在这里插入图片描述
可见RTC的核心是32位的可编程计数器,它的计数时机来自于APB1,我们来看一下APB1的时钟树在这里插入图片描述
它可以有外部的LSE直接产生,或者HSE128分频,LSI内部震荡时钟。如果使用断电仍能计数的时钟,只能使用LSE。
它可以产生三个信号,分别是RTC_Second,RTC_OverFlow RTC_ALARM.
4.RTC的寄存器
4.1控制寄存器
4.1.1RTC控制寄存器高位(RTC_CRH)
在这里插入图片描述
这三个寄存器用来执行中断请求

我们相应的对应RTC的中断使能函数来看

fun 1.

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState) //可以带入上边所所述的三个中断
{
  if (NewState != DISABLE)
  {
    RTC->CRH |= RTC_IT;
  }
  else
  {
    RTC->CRH &= (uint16_t)~RTC_IT;
  }
}

RTC控制寄存器的低位
在这里插入图片描述
我们来看5标志位对应的库函数

fun 2.

void RTC_WaitForLastTask(void)
{
  /* Loop until RTOFF flag is set */
  while ((RTC->CRL & RTC_FLAG_RTOFF) == (uint16_t)RESET)
  {
  }
}

对应来说,就是等待RTOFF操作完
4对应的库函数
fun 3

void RTC_EnterConfigMode(void)
{
  /* Set the CNF flag to enter in the Configuration Mode */
  RTC->CRL |= RTC_CRL_CNF;
}

fun 4

void RTC_ExitConfigMode(void)
{
  /* Reset the CNF flag to exit from the Configuration Mode */
  RTC->CRL &= (uint16_t)~((uint16_t)RTC_CRL_CNF); 
}

在这里插入图片描述
fun 5
rsf寄存器

/**
  * @brief  Waits until the RTC registers (RTC_CNT, RTC_ALR and RTC_PRL)
  *   are synchronized with RTC APB clock.
  * @note   This function must be called before any read operation after an APB reset
  *   or an APB clock stop.
  * @param  None
  * @retval None
  */
void RTC_WaitForSynchro(void)
{
  /* Clear RSF flag */
  RTC->CRL &= (uint16_t)~RTC_FLAG_RSF;
  /* Loop until RSF flag is set */
  while ((RTC->CRL & RTC_FLAG_RSF) == (uint16_t)RESET)
  {
  }
}

这里每当RTC_CNT寄存器和RTC_DIV寄存器由软件更新或清’0’时,此位由硬件置’1’。在APB1复位后,或APB1时钟停止后,此位必须由软件清’0’。要进行任何的读操作之前,用户程序必须等待这位被硬件置’1’,以确保RTC_CNT、RTC_ALR或RTC_PRL已经被同步。 0:寄存器尚未被同步; 1:寄存器已经被同步。
4.2 RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**
  * @brief  Sets the RTC prescaler value.
  * @param  PrescalerValue: RTC prescaler new value.
  * @retval None
  */
void RTC_SetPrescaler(uint32_t PrescalerValue)
{
  /* Check the parameters */
  assert_param(IS_RTC_PRESCALER(PrescalerValue));
  
  RTC_EnterConfigMode();
  /* Set RTC PRESCALER MSB word */
  RTC->PRLH = (PrescalerValue & PRLH_MSB_MASK) >> 16;
  /* Set RTC PRESCALER LSB word */
  RTC->PRLL = (PrescalerValue & RTC_LSB_MASK);
  RTC_ExitConfigMode();
}

设置分频数,如果晶振是32768HZ,如果prescalervalue是32768,那么计数周期就是1s
4.3
在这里插入图片描述

/**
  * @brief  Gets the RTC divider value.
  * @param  None
  * @retval RTC Divider value.
  */
uint32_t RTC_GetDivider(void)
{
  uint32_t tmp = 0x00;
  tmp = ((uint32_t)RTC->DIVH & (uint32_t)0x000F) << 16;
  tmp |= RTC->DIVL;
  return tmp;
}

4.4RTC计数器寄存器 (RTC_CNTH / RTC_CNTL)
在这里插入图片描述
在这里插入图片描述

uint32_t RTC_GetCounter(void)
{
  uint16_t tmp = 0;
  tmp = RTC->CNTL;
  return (((uint32_t)RTC->CNTH << 16 ) | tmp) ;
}
void RTC_SetCounter(uint32_t CounterValue)
{ 
  RTC_EnterConfigMode();
  /* Set RTC COUNTER MSB word */
  RTC->CNTH = CounterValue >> 16;
  /* Set RTC COUNTER LSB word */
  RTC->CNTL = (CounterValue & RTC_LSB_MASK);
  RTC_ExitConfigMode();
}

4.5RTC闹钟寄存器(RTC_ALRH/RTC_ALRL)
在这里插入图片描述

/**
  * @brief  Sets the RTC alarm value.
  * @param  AlarmValue: RTC alarm new value.
  * @retval None
  */
void RTC_SetAlarm(uint32_t AlarmValue)
{  
  RTC_EnterConfigMode();
  /* Set the ALARM MSB word */
  RTC->ALRH = AlarmValue >> 16;
  /* Set the ALARM LSB word */
  RTC->ALRL = (AlarmValue & RTC_LSB_MASK);
  RTC_ExitConfigMode();
}

5.RTC使用
head file

#ifndef _USER_RTC_H
#define _USER_RTC_H
/*头文件*/
#include "stm32f10x.h"

/*宏定义*/
//选择时钟源
#define RTC_CLOCK_SOURCE_LSE
//设置备份的寄存器
#define RTC_BKP_DXR	BKP_DR1
//写入到备份寄存器的数据
#define RTC_BKP_DATA   0xa5a5
//北京地区的时间差
#define TIME_ZOOM (8)

/*变量*/
struct rtc_time {
	int rtc_sec;
	int rtc_min;
	int rtc_hour;
	int rtc_day;
	int rtc_mon;
	int rtc_year;
	int rtc_wday;
};

/*函数*/
uint8_t RTC_Configure(uint8_t is_set,uint32_t time);
void RTC_GetYear(void);
void RTC_GetMonth(void);
void RTC_GetDay(void);
void RTC_GetHour(void);
void RTC_GetMinute(void);
void RTC_GetSecond(void);
void RTC_GetTime(void);

#endif


source file

#include "user_rtc.h"
/**
*名称:RTC获取系统时间函数
*作者:陈冲
*时间:2018年12月
*版本:1.0
*更新:1.0:无
**/
//定义的到具体时间的时间
//定义的到具体时间的时间
static uint32_t all_second = 0;			//读取寄存器的时间
static uint32_t year_second = 0;		//计算到今年的1月1日 00:00是多少秒
static uint32_t month_second = 0;		//计算到今年的某月的1日 00:00是多少秒
static uint32_t day_second = 0;			//计算到今天的00:00是多少秒
static uint32_t hour_second = 0;		//计算到今天这个小时00是多少秒
static uint32_t minute_second = 0;	//计算到今天这个小时的这个分钟00是多少秒
//定义系统时间变量
struct rtc_time systime = 
{
	0,0,0,1,1,2000,0
};
/*
*name:void RTC_GetYear()
*fun :获取当前年份
*para:void
*ret :void
*/
void RTC_GetYear()
{
	year_second = 0;
	for(systime.rtc_year = 1970;year_second<=all_second-366*60*60*24;systime.rtc_year ++)
	{
		
		if((systime.rtc_year %4 == 0 && systime.rtc_year  %100!= 0)||systime.rtc_year%400 == 0)
			year_second+= 366*60*60*24;
		else
			year_second+= 365*60*60*24;
	}
}
/*
*name:void RTC_GetMonth()
*fun :获取当前月份
*para:void
*ret :void
*/
void RTC_GetMonth()
{
	month_second = 0;
	for(systime.rtc_mon = 1;month_second <=all_second - year_second-31*24*60*60;systime.rtc_mon++)
	{
		switch(systime.rtc_mon)
		{
			case 1:case 3:case 5:case 7:case 8:case 10:case 12: month_second+=31*24*60*60;break;
			case 4:case 6:case 9:case 11: month_second+=30*24*60*60;break;
			case 2: if((systime.rtc_year%4 == 0 && systime.rtc_year  %100!= 0)||systime.rtc_year%400 == 0) month_second+=29*24*60*60; else month_second+=28*24*60*60;break;
		}
	}
}
/*
*name:void RTC_GetDay()
*fun :获取当前日
*para:void
*ret :void
*/
void RTC_GetDay()
{
	day_second = 0;
	for(systime.rtc_day = 1;day_second<= all_second - year_second - month_second - 24*60*60 ;systime.rtc_day++)
	{
		day_second += 60*24*60;
	}
}
/*
*name:void RTC_GetHour()
*fun :获取当前小时
*para:void
*ret :void
*/
void RTC_GetHour()
{
	hour_second = 0;
	for(systime.rtc_hour = 0;hour_second<= all_second - year_second - month_second - day_second -60*60;systime.rtc_hour++)
	{
		hour_second += 60*60;
	}
	systime.rtc_hour+=TIME_ZOOM;
}
/*
*name:void RTC_GetMinute()
*fun :获取当前分
*para:void
*ret :void
*/
void RTC_GetMinute()
{
	minute_second = 0;
	for(systime.rtc_min = 0;minute_second<= all_second - year_second - month_second - day_second -hour_second-60;systime.rtc_min++)
	{
		minute_second += 60;
	}
}
/*
*name:void RTC_GetSecond()
*fun :获取当前秒,并刷新其他时间
*para:void
*ret :void
*/
void RTC_GetSecond()
{
	systime.rtc_sec = all_second - year_second - month_second - day_second -hour_second -minute_second;
}
/*
*name:void RTC_GetSecond()
*fun :刷新所有时间时间
*para:void
*ret :void
*/
inline void RTC_GetTime()
{
	all_second = RTC_GetCounter();
	RTC_WaitForLastTask();
	RTC_GetYear();
	RTC_GetMonth();
	RTC_GetHour();
	RTC_GetDay();
	RTC_GetMinute();
	RTC_GetSecond();
}
/*
*name:uint8_t RTC_Configure(uint8_t is_set,uint32_t time)
*fun :RTC初始化配置函数
*para:is_set:如果要设置当前的时间戳,将其设置为1,下一次设置为0 time:当前的时间戳
*ret :1 :数据没有丢失,0:数据丢失
*/
uint8_t RTC_Configure(uint8_t is_set,uint32_t time)
{
	NVIC_InitTypeDef NVIC_InitsStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitsStruct.NVIC_IRQChannel = RTC_IRQn;
	NVIC_InitsStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitsStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitsStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitsStruct);
	uint8_t flag = 1;
	//检查数据是否丢失;
	if(BKP_ReadBackupRegister(RTC_BKP_DXR) != RTC_BKP_DATA || is_set == 1 )
	{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
		//允许访问backup区域
		PWR_BackupAccessCmd(ENABLE);
		//复位backup区域
		BKP_DeInit();
		//打开外部晶振
		RCC_LSEConfig(RCC_LSE_ON);
		//等待LSE准备好
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}
		//使用外部晶振
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		//使能RTC
		RCC_RTCCLKCmd(ENABLE);
		//等待外部时钟同步
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		RTC_SetPrescaler(32767);
		RTC_WaitForLastTask();
		BKP_WriteBackupRegister(RTC_BKP_DXR,RTC_BKP_DATA);
		RTC_WaitForLastTask();
		RTC_SetCounter(time);
		flag = 0;
	}
	RTC_ITConfig(RTC_IT_SEC,ENABLE);
	RTC_GetTime();
	return flag;
}
/*
*name:void RTC_IRQHandler(void)
*fun :RTC中断服务程序
*para:is_set:void
*ret :void
*/
/*
#include "rtc.h"
extern struct rtc_time systime;
void RTC_IRQHandler(void)
{
	  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
	  {
	    // Clear the RTC Second interrupt
	    RTC_ClearITPendingBit(RTC_IT_SEC);
			//RTC刷新时间
			RTC_GetTime();
	    // Wait until last write operation on RTC registers has finished 
	    RTC_WaitForLastTask();
	  }
}
*/


  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值