读写备份寄存器BKP与实时时钟RTC


读写备份寄存器

接线图

即接个3.3v的电源到VBT引脚
在这里插入图片描述

代码

代码效果:第一次写入备份寄存器,下载程序后再注释掉,再进行下载,之前写入的数据还会保存在备份寄存器中(还可以读到),并且复位键或拔掉主电源再插上数据也不会丢失,直到主电源备用电源同时不能供电数据才会消失

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

uint16_t Data;
int main(void)
{
	OLED_Init();
	OLED_ShowChar(1,1,'z');
	
	// 打开PWR,BKP时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
	
	// 使能PWR
	PWR_BackupAccessCmd(ENABLE);
	
	// 写备份寄存器
	//BKP_WriteBackupRegister(BKP_DR1,0X1234);
	
	// 读取备份寄存器
	Data = BKP_ReadBackupRegister(BKP_DR1);
	
	OLED_ShowHexNum(2,1,Data,4);
	while (1)
	{
		
	}
}

RTC实时时钟

接线图

在这里插入图片描述

代码

对RTC进行配置,保存于ThisRTC.c

#include "stm32f10x.h"                  // Device header
#include <time.h>
struct ThisRTC_Time{
	uint16_t year;		// 年
	uint8_t month;		// 月
	uint8_t day;		// 日
	uint8_t hour;		// 时
	uint8_t min;		// 分
	uint8_t sec;		// 秒	
};
extern struct ThisRTC_Time ThisRTC_Time1;

void ThisRTC_Init(void){
	// 打开PWR,BKP时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
	
	// 使能PWR
	PWR_BackupAccessCmd(ENABLE);
	// 如果备份寄存器数据丢失则重新初始化
	if(BKP_ReadBackupRegister(BKP_DR1) != 0X9999){
	
		// 启动LSE时钟源
		RCC_LSEConfig(RCC_LSE_ON);
		
		// 等待LSE启动完成
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET);
		
		// 选择RTC时钟源为LSE
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		
		// 使能RTC时钟
		RCC_RTCCLKCmd(ENABLE);
		
		// 等待同步
		RTC_WaitForSynchro();
		// 等待上一步写操作完成
		RTC_WaitForLastTask();
		
		// 配置分频系数,自动进入配置模式并退出
		RTC_SetPrescaler(32768-1);
		// 等待上一步写操作完成
		RTC_WaitForLastTask();
		
		void ThisRTC_SetTime(void);
		ThisRTC_SetTime();
		
		// 写入备份寄存器
		BKP_WriteBackupRegister(BKP_DR1,0X9999);
	}else{
		// 等待同步
		RTC_WaitForSynchro();
		// 等待上一步写操作完成
		RTC_WaitForLastTask();
	}
	
}


void ThisRTC_SetTime(void){
	time_t time_cnt;
	struct tm time_date;
	time_date.tm_year = ThisRTC_Time1.year - 1900;
	time_date.tm_mon = ThisRTC_Time1.month - 1;
	time_date.tm_mday = ThisRTC_Time1.day;
	time_date.tm_hour = ThisRTC_Time1.hour;
	time_date.tm_min = ThisRTC_Time1.min;
	time_date.tm_sec = ThisRTC_Time1.sec;
	// 将日期类型转换为秒计数器类型,并设置为RTC时间
	time_cnt = mktime(&time_date) - 8 * 60 * 60;
	RTC_SetCounter(time_cnt);
	// 等待上一步写操作完成
	RTC_WaitForLastTask();
}


void ThisRTC_ReadTime(void){
	time_t time_cnt;
	struct tm time_date;
	time_cnt = RTC_GetCounter() + 8 * 60 * 60;	// 加时区偏移变为北京时间
	time_date = *localtime(&time_cnt);
	ThisRTC_Time1.year = time_date.tm_year + 1900;
	ThisRTC_Time1.month = time_date.tm_mon + 1;
	ThisRTC_Time1.day = time_date.tm_mday;
	ThisRTC_Time1.hour = time_date.tm_hour;
	ThisRTC_Time1.min = time_date.tm_min;
	ThisRTC_Time1.sec = time_date.tm_sec;
}

头文件ThisRTC.h声明

#ifndef __THISRTC_H
#define __THISRTC_H
// 存放时间结构体
struct ThisRTC_Time{
	uint16_t year;	// 年
	uint8_t month;	// 月
	uint8_t day;		// 日
	uint8_t hour;		// 时
	uint8_t min;		// 分
	uint8_t sec;		// 秒	
};
struct ThisRTC_Time ThisRTC_Time1 = {2024,10,27,5,2,0};

void ThisRTC_Init(void);
void ThisRTC_SetTime(void);
void ThisRTC_ReadTime(void);


#endif

主函数内容

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

int main(void)
{
	OLED_Init();
	ThisRTC_Init();
	OLED_ShowString(1,1,"Date:XXXX-XX-XX");
	OLED_ShowString(2,1,"Time:XX:XX:XX");
	OLED_ShowString(3,1,"CNT :");
	OLED_ShowString(4,1,"DIV :");
	while (1)
	{
		ThisRTC_ReadTime();
		OLED_ShowNum(1,6,ThisRTC_Time1.year,4);
		OLED_ShowNum(1,11,ThisRTC_Time1.month,2);
		OLED_ShowNum(1,14,ThisRTC_Time1.day,2);
		OLED_ShowNum(2,6,ThisRTC_Time1.hour,2);
		OLED_ShowNum(2,9,ThisRTC_Time1.min,2);
		OLED_ShowNum(2,12,ThisRTC_Time1.sec,2);
		OLED_ShowNum(3,6,RTC_GetCounter(),10);
		OLED_ShowNum(4,6,RTC_GetDivider(),6);		// 余数寄存器
	}
}


  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一份基于STM32的RTC校准代码,使用备份寄存器进行校准: ```c #include "stm32f10x.h" // RTC时钟频率 #define RTC_CLOCK_FREQ 32768 void RTC_Config(void) { // 使能PWR和BKP外设时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); // 使能备份区域访问 PWR_BackupAccessCmd(ENABLE); // 检查备份寄存器的值是否合法 if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) { // 如果不合法,将RTC重置为默认时间并设置校准值为0 RCC_BackupResetCmd(ENABLE); RCC_BackupResetCmd(DISABLE); // 使能LSE时钟 RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {} // RTC时钟源为LSE RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // 使能RTC时钟 RCC_RTCCLKCmd(ENABLE); // 等待RTC时钟启动 RTC_WaitForSynchro(); // 设置RTC预分频器为32767,使得RTC时钟频率为1Hz RTC_SetPrescaler(RTC_CLOCK_FREQ-1); // 初始化RTC时间为2022年1月1日0时0分0秒 RTC_SetCounter(0); RTC_SetDate(1); RTC_SetMonth(1); RTC_SetYear(22); RTC_SetHour(0); RTC_SetMinute(0); RTC_SetSecond(0); // 将校准值设置为0 RTC_CalibOutputConfig(RTC_CalibOutput_1Hz); RTC_CalibConfig(RTC_CalibSign_Positive, 0, 0); // 备份寄存器 BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); } else { // 如果备份寄存器的值合法,恢复RTC时钟源为LSE RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); } } // 获取当前的RTC时间 void RTC_GetTime(uint16_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second) { RTC_TimeTypeDef RTC_TimeStruct; RTC_DateTypeDef RTC_DateStruct; RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct); RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct); *year = RTC_DateStruct.RTC_Year; *month = RTC_DateStruct.RTC_Month; *day = RTC_DateStruct.RTC_Date; *hour = RTC_TimeStruct.RTC_Hours; *minute = RTC_TimeStruct.RTC_Minutes; *second = RTC_TimeStruct.RTC_Seconds; } // 设置RTC校准值 void RTC_SetCalibration(int8_t calib) { RTC_CalibOutputConfig(RTC_CalibOutput_1Hz); if (calib > 0) { RTC_CalibConfig(RTC_CalibSign_Positive, calib, RTC_CALIBDIV_32); } else if (calib < 0) { RTC_CalibConfig(RTC_CalibSign_Negative, -calib, RTC_CALIBDIV_32); } else { RTC_CalibConfig(RTC_CalibSign_Positive, 0, RTC_CALIBDIV_1); } } ``` 该代码中包含了以下功能: - 初始化RTC,如果备份寄存器的值不合法,则将RTC时间设置为默认值,并将校准值设置为0; - 获取当前的RTC时间; - 设置RTC校准值。 在使用该代码时,您可以根据自己的需求修改RTC的默认时间和校准值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值