RTC讲解

发布时间:2024年01月18日

RTC(Real Time Clock)实时时钟

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

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒 后,RTC的设置和时间维持不变,需要注意前提得有备用电源VBAT供电保持走时,即VDD(2.0~3.6V)断电后可借助VBAT(1.8~3.6V)供电继续走时。

参考手册给出的结构框图如下:

简单介绍流程,就是一个定时器根据时钟确定每秒钟增加多少秒,往往我们是用于看时间,也就是说对于实际分频过后的时钟要有为:1HZ,才能使得定时器每秒钟加1。我们可以通过time.h对时间戳/计数值处理来得到当前的日期时间。

1.时钟来源:我们实际选择时钟源,可选择三种RTC时钟源HSE时钟除以128(通常为8MHz/128)? ? , LSE振荡器时钟(通常为32.768KHz)? ? , LSI振荡器时钟(40KHz)三种

对照手册:

我们也可以通过时钟树看出:

2.RTC实际配置步骤:

1.开启RTC访问权

对于stm32来说,实际正常运行不会启动RTC,因为RTC主要由备份电源VBAT供电使用,所以我们使用时候需要开启访问,而BKP和RTC在stm32当中是统一的,开启RTC就相当于开启BKP同样开启BKP也相当于开启RTC。

2.设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问,需要我们手动开启PWR的DBP位,这样才能对RTC写入操作。

3.选择时钟源:对于RTC来说,我们实际上LSE是专门用于RTC的时钟信号,对应外部晶振32.768KHZ。其他主要是作为当第一种无法使用的备份选择。本质上它主要是由备份电源VBAT供电。

4.等待时钟同步,以及写入完成

注意:每一次写入操作都需要我们对等待写入完成,调用库等待函数,或者等待相应标志位RTOFF置0。

5.配置计数器CNT(如果需要余数寄存器也可以在此配置,不过写入后需要等待写入完成)

主要是写入当前时间戳,不知道可以参考之前时间戳讲解。

6.等待写入完成。

实际也可以使用寄存器,不过我使用的是库函数,寄存器可以参考手册如下:

实例代码:

我使用了两种,一种数组,一种时间戳,具体可以根据需要采用

方案一:时间戳:

MYRTC.h

#ifndef __MYRTC_H__
#define __MYRTC_H__
extern struct tm tm_RTC;

void MyRTC_Init(void);

void RTC_SetTime(void);

void RTC_readtime(void);
#endif

MYRTC.c


uint32_t RTC_time=1705582640;//此时此刻的时间戳
struct tm tm_RTC;
void RTC_SetTime(void);
void MyRTC_Init(void)
{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//开启RTC时钟
		
	  PWR_BackupAccessCmd(ENABLE);;//设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问
		
			RCC_LSEConfig(RCC_LSE_ON);//开启LSE

		 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!= SET);
			RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择RTC时钟源:外部时钟源
			RCC_RTCCLKCmd(ENABLE);//使能时钟
		
			RTC_WaitForSynchro();//等待RTC_CNT, RTC_ALR and RTC_PRL同步
			RTC_WaitForLastTask();//等待RTOFF置1,写操作完成
		
		
			RTC_SetPrescaler(32768-1);//配置预分频器系数
			RTC_WaitForLastTask();
			
			RTC_SetTime();
			RTC_WaitForLastTask();
			BKP_WriteBackupRegister(BKP_DR1, 0xFFFF);
	
	
	
}
void RTC_SetTime(void)
{
	RTC_SetCounter(RTC_time+8*60*60);
	
}
void RTC_readtime(void)
{
	uint32_t Read_time=0;
	Read_time=RTC_GetCounter();
	RTC_WaitForLastTask();
	tm_RTC=*localtime(&Read_time);
}

方案二:数组

MYRTC.h:

#ifndef __MYRTC_H
#define __MYRTC_H

extern uint16_t MYRTC_Time[];

void MYRTC_Init(void);
void MYRTC_SetTime(void);
void MYRTC_ReadTime(void);

#endif

MYRTC.c:

#include "stm32f10x.h"                  // Device header
#include <time.h>

uint16_t MYRTC_Time[] = {2024, 1, 18, 22, 53, 55};

void MYRTC_SetTime(void);

void MYRTC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	
	PWR_BackupAccessCmd(ENABLE);
	

		RCC_LSEConfig(RCC_LSE_ON);
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		RTC_SetPrescaler(32768 - 1);
		RTC_WaitForLastTask();
		
		MYRTC_SetTime();


}
void MYRTC_SetTime(void)
{
	time_t time_cnt;
	struct tm time_date;
	
	time_date.tm_year = MYRTC_Time[0] - 1900;
	time_date.tm_mon = MYRTC_Time[1] - 1;
	time_date.tm_mday = MYRTC_Time[2];
	time_date.tm_hour = MYRTC_Time[3];
	time_date.tm_min = MYRTC_Time[4];
	time_date.tm_sec = MYRTC_Time[5];
	
	time_cnt = mktime(&time_date) - 8 * 60 * 60;
	
	RTC_SetCounter(time_cnt);
	RTC_WaitForLastTask();
}

void MyRTC_ReadTime(void)
{
	time_t time_cnt;
	struct tm time_date;
	
	time_cnt = RTC_GetCounter() + 8 * 60 * 60;
	
	time_date = *localtime(&time_cnt);
	
	MYRTC_Time[0] = time_date.tm_year + 1900;
	MYRTC_Time[1] = time_date.tm_mon + 1;
	MYRTC_Time[2] = time_date.tm_mday;
	MYRTC_Time[3] = time_date.tm_hour;
	MYRTC_Time[4] = time_date.tm_min;
	MYRTC_Time[5] = time_date.tm_sec;
}

时间的转化当中涉及一定偏移,不知道可以参考之前时间戳讲解。

文章来源:https://blog.csdn.net/qq_59671069/article/details/135685419
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。