stm32---实时时钟(RTC,BKP, PWR)

图文概述:

代码:

MyRTC.c:

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

/* 设置显示的初始的日期时间结构体 */
struct tm MainTime = {57, 59, 23, 9, 10, 2023}; //秒 分 时 日 月(偏移量-1) 年(从1970开始算,有偏移)

void MyRTC_SetTime(void);

/**
  * @brief  MyRTC_Init---对RTC进行初始化
  * @param  无
  * @retval 无
  */
void MyRTC_Init(void)
{
	//1.开启PWR和BKP外设的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	//2.PWR使能BKP
	PWR_BackupAccessCmd(ENABLE);

	/*
	判断备用电源有没有断电:若断电过则备用寄存器的值会清除,
	就需要重新初始化,若没有断电过则不需要再进行初始化
	(0xA5A5相当于一个标志,用来查看是否还存在备用寄存器内)
	*/
	if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
	{
		//3.开启LSE时钟,并等待LSE时钟启动完成
		RCC_LSEConfig(RCC_LSE_ON);
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		//4.选择RTCCLK时钟源
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择LSE作为RTCCLK的时钟源
		RCC_RTCCLKCmd(ENABLE); //使能时钟
		
		//5.调用等待函数(等待同步和等待上一次写入操作完成)---防止因为时钟不同步,产生BUG
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		//6.配置预分频器
		RTC_SetPrescaler(32768 - 1); //为了让LSE的32.768kHz频率产生1Hz的频率
		RTC_WaitForLastTask();//等待上一次写入操作完成
		
		//7.设置初始化的时间
		MyRTC_SetTime();
		
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
	}
	else
	{
		//调用等待函数(等待同步和等待上一次写入操作完成)---防止因为时钟不同步,产生BUG
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
	}
}

/**
  * @brief  MyRTC_SetTime---设置时间(即对初始的日期时间结构体中的变量值转换为秒数存放在RTC计数寄存器)
  * @param  无
  * @retval 无
  */
void MyRTC_SetTime(void)
{
	time_t time_cnt;

	//1.将日期时间转换为秒数
	MainTime.tm_year -= 1900; //年份需要减去1900偏移量
	MainTime.tm_mon -= 1;	  //月份需要减去1偏移量
	time_cnt = mktime(&MainTime) - 8 * 60 * 60;//mktime---日期时间转换为秒数(规范为北京东八区时间)

	//2.设置秒数到RTC计数寄存器
	RTC_SetCounter(time_cnt); //将秒数写入到RTC计数寄存器中
	RTC_WaitForLastTask();//等待上一次写入操作完成
}

/**
  * @brief  MyRTC_ReadTime---读取数据(即读取RTC计数寄存器中的值并且转换为日期时间结构体中的变量值)
  * @param  无
  * @retval 无
  */
void MyRTC_ReadTime(void)
{
	time_t time_cnt;
	
	//1.获取RTC计数寄存器的秒数
	time_cnt = RTC_GetCounter() + 8 * 60 * 60;//(规范为北京东八区时间)

	//2.将秒数转换为日期时间
	MainTime = *localtime(&time_cnt);
	MainTime.tm_year += 1900; //年份需要加上1900偏移量
	MainTime.tm_mon += 1;	  //月份需要加上1偏移量
}


MyRTC.h:

#ifndef __MYRTC_H
#define __MYRTC_H

#include <time.h>

extern struct tm MainTime;

void MyRTC_Init(void);
void MyRTC_SetTime(void);
void MyRTC_ReadTime(void);


#endif

main.c:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

/*
	显示实时时钟,只要VBT备用电源不断电,就可以一直计数下去
*/
int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "    -  -");
	OLED_ShowString(2, 1, "  :  :");
	OLED_ShowString(3, 1, "CNT:");
	OLED_ShowString(4, 1, "DIV:");
	
	MyRTC_Init();

	while(1)
	{
		MyRTC_ReadTime();
		OLED_ShowNum(1, 1, MainTime.tm_year, 4);
		OLED_ShowNum(1, 6, MainTime.tm_mon, 2);
		OLED_ShowNum(1, 9, MainTime.tm_mday, 2);
		OLED_ShowNum(2, 1, MainTime.tm_hour, 2);
		OLED_ShowNum(2, 4, MainTime.tm_min, 2);
		OLED_ShowNum(2, 7, MainTime.tm_sec, 2);
		
		//获取计数寄存器的值
		OLED_ShowNum(3, 5, RTC_GetCounter(), 10);   
		//获取余数寄存器的值(重装初始值由RTC预分频寄存器设置相关,自减直至每次越出0则计数寄存器+1)
		OLED_ShowNum(4, 5, RTC_GetDivider(), 10);   
		
	}
}

关键步骤:

1.开启PWR和BKP外设的时钟以及PWR使能BKP:

	//1.开启PWR和BKP外设的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	//2.PWR使能BKP
	PWR_BackupAccessCmd(ENABLE);

对应下图注意事项:

 

2. 开启LSE时钟,并等待LSE时钟启动完成。并且选择RTCCLK时钟源为LSE

		//3.开启LSE时钟,并等待LSE时钟启动完成
		RCC_LSEConfig(RCC_LSE_ON);
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		//4.选择RTCCLK时钟源
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择LSE作为RTCCLK的时钟源
		RCC_RTCCLKCmd(ENABLE); //使能时钟

对应下图操作:

 

3. 调用等待函数(等待同步和等待上一次写入操作完成)---防止因为时钟不同步,产生BUG

		//5.调用等待函数(等待同步和等待上一次写入操作完成)---防止因为时钟不同步,产生BUG
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();

 对应下图注意事项:

4. 配置预分频器

		//6.配置预分频器
		RTC_SetPrescaler(32768 - 1); //为了让LSE的32.768kHz频率产生1Hz的频率
		RTC_WaitForLastTask();//等待上一次写入操作完成

 对应下图操作:

5. 设置时间(即对初始的日期时间结构体中的变量值转换为秒数存放在RTC计数寄存器)

/**
  * @brief  MyRTC_SetTime---设置时间(即对初始的日期时间结构体中的变量值转换为秒数存放在RTC计数寄存器)
  * @param  无
  * @retval 无
  */
void MyRTC_SetTime(void)
{
	time_t time_cnt;

	//1.将日期时间转换为秒数
	MainTime.tm_year -= 1900; //年份需要减去1900偏移量
	MainTime.tm_mon -= 1;	  //月份需要减去1偏移量
	time_cnt = mktime(&MainTime) - 8 * 60 * 60;//mktime---日期时间转换为秒数(规范为北京东八区时间)

	//2.设置秒数到RTC计数寄存器
	RTC_SetCounter(time_cnt); //将秒数写入到RTC计数寄存器中
	RTC_WaitForLastTask();//等待上一次写入操作完成
}

对应下图操作:

 

补充:

在MyRTC_Init初始化函数中,需要判断备用是否断电,如果没有断电则每次复位时不需要重新设置时间,若备用电源断电过,则下次复位时,需要重新设置时间,这个时候就需要加个if条件判断,根据BKP的备份寄存器特性来完成,在BKP的备份寄存器存入一个数值(断电标志),若下一次复位时进行MyRTC_Init初始化函数,先检查BKP的备份寄存器中的数值(断电标志)是否还存在,若被清除,则证明备用电源断电过。

/*
	判断备用电源有没有断电:若断电过则备用寄存器的值会清除,
	就需要重新初始化,若没有断电过则不需要再进行初始化
	(0xA5A5相当于一个标志,用来查看是否还存在备用寄存器内)
	*/
	if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
	{
		//3.开启LSE时钟,并等待LSE时钟启动完成
		RCC_LSEConfig(RCC_LSE_ON);
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		//4.选择RTCCLK时钟源
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择LSE作为RTCCLK的时钟源
		RCC_RTCCLKCmd(ENABLE); //使能时钟
		
		//5.调用等待函数(等待同步和等待上一次写入操作完成)---防止因为时钟不同步,产生BUG
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		//6.配置预分频器
		RTC_SetPrescaler(32768 - 1); //为了让LSE的32.768kHz频率产生1Hz的频率
		RTC_WaitForLastTask();//等待上一次写入操作完成
		
		//7.设置初始化的时间
		MyRTC_SetTime();
		
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
	}
	else
	{
		//调用等待函数(等待同步和等待上一次写入操作完成)---防止因为时钟不同步,产生BUG
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
	}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于STM32F4xx的RTC实时时钟代码,包括初始化和设置时间的函数: ```c #include "stm32f4xx.h" void RTC_Init(void) { /* 使能PWRBKP时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); /* 解锁BKP区域 */ PWR_BackupAccessCmd(ENABLE); /* 复位BKP区域 */ BKP_DeInit(); /* 使能LSE时钟 */ RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) { } /* 选择LSE作为RTC时钟源 */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); /* 使能RTC时钟 */ RCC_RTCCLKCmd(ENABLE); /* 等待RTC同步 */ RTC_WaitForSynchro(); /* 设置RTC预分频器 */ RTC_SetPrescaler(32767); /* 等待RTC同步 */ RTC_WaitForSynchro(); } void RTC_SetTime(uint8_t hour, uint8_t minute, uint8_t second) { RTC_TimeTypeDef RTC_TimeStructure; /* 等待RTC同步 */ RTC_WaitForSynchro(); /* 设置RTC时间 */ RTC_TimeStructure.RTC_Hours = hour; RTC_TimeStructure.RTC_Minutes = minute; RTC_TimeStructure.RTC_Seconds = second; RTC_TimeStructure.RTC_H12 = RTC_H12_AM; RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure); /* 等待RTC同步 */ RTC_WaitForSynchro(); } ``` 在主函数中,可以先调用RTC初始化函数,然后再调用RTC设置时间函数,例如: ```c int main(void) { /* 初始化RTC */ RTC_Init(); /* 设置RTC时间为12:34:56 */ RTC_SetTime(12, 34, 56); while (1) { } } ``` 需要注意的是,RTC模块需要连接外部低速晶振(LSE),并且需要在STM32的RCC寄存器中设置LSE作为RTC时钟源。同时,还需要在PWR寄存器中解锁BKP区域,才能够使用RTC模块。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值