#include "stm32f10x.h"
#include <time.h>
uint16_t MyRTC_Time[] = {2023,1,1,23,59,55};//2023超过了uint8_t数据的范围 所以定义成16位
//将数组的时间刷新到RTC外设里 调用读取函数 将RTC外设的时间刷新到这个数组里
//值得注意的是:如果是个位数 前面不要补0 因为在C语言中以0开头的是8进制 虽然8进制的1和10进制的1一样
//但是如果写09的时候会报错,因为在八进制中数字9是无效的 所以在十进制的前边不可以随意补0
void MyRTC_Init(void)
{
//1.开启PWR和BKP的时钟 使能BKP和RTC的访问
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
if(BKP_ReadBackupRegister(BKP_DR1) != 0xa5a5)//第一次上电时 或者系统完全断电之后 BKP_DR1默认是0
{ //if成立执行初始化 初始化之后置BKP标志位为a5a5 下次读到这个数据说明备用电池没断电
//2.开启LSE时钟 并等待LSE时钟启动完成
//共3个参数 LSE_OFF表示LSE振荡器关闭 LSE_ON表示打开
//LSE_Bypass 表示时钟旁路 意思是不接晶振 直接从OSC32_IN这个引脚输入一个指定频率的信号当做时钟源
RCC_LSEConfig(RCC_LSE_ON);
//RCC_LSICmd(ENABLE);//启动LSI
//等待LSE启动完成
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
//while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);//等待LSI
//选择RTCCLK时钟源
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
//RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//时钟修改为LSI
//使能时钟
RCC_RTCCLKCmd(ENABLE);
//等待同步 函数内部自带while等待 调用即可实现等待效果
RTC_WaitForSynchro();
//等待上一次写入操作完成
RTC_WaitForLastTask();
//要将LSE的32.768KHz频率分频为1分频,其中 减1 是因为计数值包含0
RTC_SetPrescaler(32768 - 1);//自带进入和退出配置模式的代码
//RTC_SetPrescaler(40000 - 1);//LSI时钟源40KHz
RTC_WaitForLastTask();
//给一个32位的秒计数器
RTC_SetCounter(1672588795);
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1,0xa5a5);
}
else//如果已经初始化过了 则无需初始化 但是最好执行等待的函数防止意外
{
RTC_WaitForSynchro();
RTC_WaitForLastTask();
}
}
void MyRTC_SetTime(void)
{
time_t time_cnt;
struct tm time_date;
//1.把数组指定的时间填充到struct tm结构体里
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_sec = MyRTC_Time[4];
time_date.tm_min = MyRTC_Time[5];
//2.使用mktime函数得到秒数
time_cnt = mktime(&time_date);
//3.将秒数写入到RTC的CNT中
RTC_SetCounter(time_cnt);
RTC_WaitForLastTask();
}
void MyRTC_ReadTime(void)
{
time_t time_cnt;
struct tm time_date;
//1.RTC_GetCounter读取CNT秒数
time_cnt = RTC_GetCounter();
//2.使用localtime函数得到日期时间
time_date = *localtime(&time_cnt); //返回值是struct tm* 所以需要先取内容
//3.将time_date的日期时间转移到数组里 操作和上边相反即可
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_sec ;
MyRTC_Time[5] = time_date.tm_min ;
}
//配置LSE外部低速时钟
void RCC_LSEConfig(uint8_t RCC_LSE);
//配置LSI内部低速时钟
void RCC_LSICmd(FunctionalState NewState);
//RTCCLK配置 用于选择RTCCLK的时钟源
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);
//启动RTCCLK 在调用上边的选择时钟函数之后 需要调用Cmd进行使能
void RCC_RTCCLKCmd(FunctionalState NewState);
//获取标志位 调用启动时钟的函数之后需要等待标志位置1 时钟才算启动完成工作稳定
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);
//配置中断输出
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);
//进入配置模式 CNF位置1后才能写入寄存器
void RTC_EnterConfigMode(void);
//退出配置模式
void RTC_ExitConfigMode(void);
//获取CNT计数器的值 可读取时钟
uint32_t RTC_GetCounter(void);
//写入CNT计数器的值 可设置时间
void RTC_SetCounter(uint32_t CounterValue);
//写入预分频器 会写入预分频器的PRL重装寄存器中 用于配置预分频器的分频系数
void RTC_SetPrescaler(uint32_t PrescalerValue);
//写入闹钟值 配置闹钟
void RTC_SetAlarm(uint32_t AlarmValue);
//读取预分频器中的DIV余数寄存器 是一个自减计数器 为了得到更细致的时间
uint32_t RTC_GetDivider(void);
//等待同步 等待RSF置1
void RTC_WaitForLastTask(void);
//下边四个均为与标志位相关的函数
void RTC_WaitForSynchro(void);
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
void RTC_ClearFlag(uint16_t RTC_FLAG);
ITStatus RTC_GetITStatus(uint16_t RTC_IT);
void RTC_ClearITPendingBit(uint16_t RTC_IT);