#include "rtc.h"
#if 1
//关闭半主机模式
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE{
int handle;
};
FILE __stdin, __stdout, __stderr;
//FILE __stdin;
//避免使用半主机模式
void _sys_exit(int x)
{
x=x;
}
/*重写fputc*/
int fputc(int ch, FILE *f)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //通过串口把ch给发送出去
USART_SendData(USART1,ch);
return ch;
}
int fgetc(FILE *f){
char ch;
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
ch=USART_ReceiveData(USART1);
return (int)ch;
}
int ferror(FILE * f){
return EOF;
}
void _ttywrch(int ch){
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
USART_SendData(USART1,ch);
}
//void _sys_exit(int return_code){
// while(1);
//}
#endif
cal calendar;
int const month_table[12] ={31,28,31,30,31,30,31,31,30,31,30,31};
__IO uint8_t TimeDisplay;
//RTC内设配置
void rtc_init(){
uint32_t t;
//使能rcu_bkpi时钟,pwr电源,bkp后备区域
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
//使能备份区域,允许访问备份(Backup)区域
PWR_BackupAccessCmd(ENABLE);
//备份域复位
BKP_DeInit();
//使能外部低速时钟,32.768k
RCC_LSEConfig(RCC_LSE_ON);
//等待外部低速时钟稳定
while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)&& (t<10)){
t++;
}
//选择LSE作为RTC的时钟源
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
//使能RTC时钟
RCC_RTCCLKCmd(ENABLE);
//等待RTC最后一次操作完成
RTC_WaitForLastTask();
//等待寄存器与APB1时钟同步,因为RTC时钟是低速的,内环时钟是高速的,所以要同步
RTC_WaitForSynchro();
//等待RTC最后一次操作完成
RTC_WaitForLastTask();
//使能RTC的秒中断
RTC_ITConfig(RTC_IT_SEC,ENABLE);
//等待RTC最后一次操作完成
RTC_WaitForLastTask();
//设置预分频寄存器,时间周期是1秒 = 32.768k/32768+1--------(RTCCLK/RTC_PR)
RTC_SetPrescaler(32768-1);
//等待RTC最后一次操作完成
RTC_WaitForLastTask();
}
void RTC_NVIC_Config(void){
NVIC_InitTypeDef NVIC_InitStructure;
//设置优先级组为1,抢占1位(0-1),从3位(0-7)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//设置优先级通道
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void clockinit_RTC(){
RTC_NVIC_Config();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
//识别是不是后背备份区域
if(BKP_ReadBackupRegister(BKP_DR1)!=0XA5A5){
//通过判断后背寄存器的值来判断是否是系统第一次上电
printf("RTC没有被配置过");
//是的话就进行RTC配置,设置初试时间
rtc_init();
printf("RTC正在配置");
Time_Adjust();
BKP_WriteBackupRegister(BKP_DR1,0xA5A5);
}else{
//看是否是系统掉电
if(RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET){
printf("Power On Resetm occurred...");
}
//看是否是复位引脚引起的复位
else if(RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){
printf("External Reset occured...");
}
printf("No need to configure RTC...");
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();
}
RCC_ClearFlag();
Time_Show();
}
//RTC初始化(配置函数,Set引参,Get获得时间)
//设置时间函数
void Time_Adjust(void){
//等待RTC最后一次操作完成
RTC_WaitForLastTask();
//将秒数存取寄存器
RTC_SetCounter(rtc_timeSet(2023,9,22,14,30,0));
//等待RTC最后一次操作完成
RTC_WaitForLastTask();
}
//用设置的时间去获得秒,我们使用秒中断
uint32_t rtc_timeSet(uint16_t syear,uint8_t smonth,uint8_t sdays,uint8_t shour,uint8_t sminute,uint8_t ssecond){
uint16_t old_year=1970;
//uint32_t all_second=0;
uint16_t days=0;
uint8_t month=0;
uint32_t second=0;
//时间大于一年的计算
while(old_year<syear){
if(IS_temp_year(old_year)){
days += 366;
}else{
days +=365;
}
old_year++;
}
//时间不足一年的计算
for(;month<smonth;month++){
if(!IS_temp_year(syear)){
days += month_table[month];
}else{
if(month==1){
days = days + month_table[month]+1;
}else{
days += month_table[month];
}
}
}
days += sdays;
//得到年月日的秒数,一天有86400秒
second = days * 86400;
//不足一天的秒数--时
second +=shour * 3600;
//不足一天的秒数--分
second += sminute * 60;
//不足一天的秒数--秒
second += ssecond;
return second;
}
//用得到的秒数去计算现在的日期
uint8_t rtc_timeGet(){
uint32_t getsecond = RTC_GetCounter();
uint16_t gyear = 1970;
uint16_t gdays = 0;
uint8_t gmonth = 0;
uint8_t ghour = 0;
uint8_t gminute = 0;
uint16_t gsecond = 0;
gdays = getsecond / 86400;
while(gdays < 365){
if(IS_temp_year(gyear)){
gdays -= 366;
}else{
gdays -= 365;
}
gyear++ ;
}
while(gdays >= 28){
if(IS_temp_year(gyear)){
gdays = gdays - month_table[gmonth]-1;
}else{
gdays -= month_table[gmonth];
}
gmonth++ ;
}
calendar.year = gyear;
calendar.month = gmonth;
calendar.day = (uint8_t)gdays;
//不足一天的秒数
gsecond = getsecond % 86400 ;
ghour = gsecond / 3600;
gminute = (gsecond % 3600) / 60;
gsecond = (gsecond % 3600) %60 ;
calendar.hour = ghour;
calendar.minute = gminute;
calendar.second = (uint8_t)gsecond;
return 0;
}
//判断现在的年份是不是闰年
int IS_temp_year(uint16_t year){
if(year%4==0){
if(year%100!=0){
return 1;
}else{
return 0;
}
}else{
if(year%400==0){
return 1;
}else{
return 0;
}
}
}
void Time_Show(void){
printf("\n\r");
while(1){
//秒标志位
if(TimeDisplay == 1){
//Time_Display(RTC_GetCounter());
Time_Display2();
TimeDisplay = 0;
}
}
}
void Time_Display(uint32_t time){
uint32_t hh=0,mm=0,ss=0;
/*当时间走到23:59:59,RTC复位,计数值清零*/
if(RTC_GetCounter() == 0x0001517f){ //(23*3600=82800)+(59*60=3540)+(59)=86399变十六进制是0x0001517f
RTC_SetCounter(0x0);
RTC_WaitForLastTask();
}
hh=time/3600;
mm=(time%3600)/60;
ss=(time%3600)%60;
}
void RTC_IRQHandler(void){
//秒中断是否开启
if(RTC_GetITStatus(RTC_IT_SEC)==SET){
/*清除秒中断标识位*/
RTC_ClearITPendingBit(RTC_IT_SEC);
/*置1s标志位*/
TimeDisplay=1;
RTC_WaitForLastTask();
// //显示时间
// Time_Display2();
}
RTC_WaitForLastTask();
}
void Time_Display2(void){
rtc_timeGet();
printf("Now time is: %d-%d-%d %d:%d:%d\r\n", calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute, calendar.second);
}