一、BKP
RTC与备份寄存器BKP一般复位后,为了防止篡改备份数据,默认都是禁止访问的,如果想要访问,就要手动开启。
首先,来介绍一下BKP库函数
重新初始化BKP,使之恢复默认值,当你VDD、VBAT不断电,但你想要复位时使用
void BKP_DeInit(void);
防入侵配置
void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel);
使能防入侵
void BKP_TamperPinCmd(FunctionalState NewState);
BKP中断配置
void BKP_ITConfig(FunctionalState NewState);
RTC输出配置
void BKP_RTCOutputConfig(uint16_t BKP_RTCOutputSource);
设置RTC校准值
void BKP_SetRTCCalibrationValue(uint8_t CalibrationValue);
写入BKP_DR
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);
读出BKP_DR的值
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);
想要使用BKP很简单,只需要开启PWR与BKP的时钟,当然,除了这,你想要读写BKP,还需要使能BKP的访问。下方几行代码就是BKP的简单使用了
uint16_t DR_Value;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_WriteBackupRegister(BKP_DR1,0x1234);
DR_Value=BKP_ReadBackupRegister(BKP_DR1);
二、RTC
1、开启RTC、BKP的访问
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
2、开启LSE振荡器,并等待其起振完毕
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=1)
3、开启RTC时钟
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
4、同步PCLK与RTCCLK
若不同步,在复位时将会读取错误数据0。需等待其同步才能进行读写
RTC_WaitForSynchro();
RTC_WaitForLastTask();
5、设置PRL预分频器的值
LSE为32.768KHZ,输出1HZ就需要32768-1分频
RTC_SetPrescaler(32768-1);
RTC_WaitForLastTask();
6、设置CNT时间戳的值
RTC_SetCounter(1690303080);
RTC_WaitForLastTask();
到了这里RTC算是初始化完成了,但是复位后会重新初始化,数据将会回到初始值,想要复位或者VDD断电仍然保持运行,只需要加一个BKP_DR的判断即可,若写入DR中的数据没有变化,就不进行初始化。下面时完整的程序
void MyRTC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
if(BKP_ReadBackupRegister(BKP_DR2)!=0x1234)
{
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=1)
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(32768-1);
RTC_WaitForLastTask();
RTC_SetCounter(1690303080);
RTC_WaitForLastTask();
}
else
{
RTC_WaitForSynchro();
RTC_WaitForLastTask();
}
BKP_WriteBackupRegister(BKP_DR2,0x1234);
}
在设置CNT时,要输入一大串数字,无疑时非常麻烦的,现在还需要的就是一个将日期时间设置到CNT与将CNT中的值读出来转换成日期时间的封装函数,在此需要用到 time.h
uint16_t MyRTC_Time[6]={2023,7,25,12,0,0};
void MyRTC_SetTime(void)
{
time_t Count;
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];
Count = mktime(&Time_Date);
RTC_SetCounter(Count);
RTC_WaitForLastTask();
}
void MyRTC_ReadTime(void)
{
time_t Count;
struct tm Time_Date;
Count=RTC_GetCounter();
Time_Date= * localtime(&Count);
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;
}