部分GD32RTC只有一个存储寄存器,官方例程也只能存储时分秒,故此特别编写UTC时间,兼容上年月日周时分秒
---------------------------------------------------------------------------------------C---------------------------------------------------------------------------------------
#include "my_rtc.h"
const unsigned int NonleapYearMonth[12] = { 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 };
const unsigned int LeapYearMonth[12] = { 31, 31 + 29, 31 + 29 + 31, 31 + 29 + 31 + 30, 31 + 29 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 };
uint8_t my_rtc_cf(void)
{
if(bkp_data_read(BKP_DATA_0) != 0xA5A5)
return 0;
else
return 1;
}
void my_rtc_sync(void)
{
rcu_periph_clock_enable(RCU_BKPI);
rcu_periph_clock_enable(RCU_PMU);
pmu_backup_write_enable();
rtc_register_sync_wait();
rtc_lwoff_wait();
rcu_all_reset_flag_clear();
}
static unsigned char alg_IsLeapYear(unsigned int year)
{
if((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) //能被4整除,不能被百整除,能被400整除。
{
return 1; //闰年
}
else
{
return 0; //平年
}
}
my_timejg alg_Utc2LocalTime(unsigned int UtcVal, char TimeZone)
{
unsigned int i = 0;
my_timejg LocalTime;
unsigned int Hour,Days,Year;
LocalTime.my_seconds = UtcVal%60; //得到秒余数
LocalTime.my_minutes = (UtcVal/60)%60; //得到整数分钟数
Hour = (UtcVal/60)/60; //得到整数小时数
LocalTime.my_hour = Hour%24+TimeZone; //得到小时余数+时区
if(LocalTime.my_hour>23)
{
LocalTime.my_hour-=24;
Days=Hour/24+1;
}
else
{
Days=Hour/24;
}
LocalTime.my_week=(Days+4)%7; //计算星期,0-表示星期天 注:1970-1-1 是星期4
//注:400年=146097天,100年=36524天,4年=1461天
Year = 1970; //utc时间从1970开始
Year += (Days/146097)*400;
Days %= 146097; //计算400年内的剩余天数
Year += (Days/36525)*100;
Days %= 36525;
Year += (Days/1461)*4;
Days %= 1461; //计算4年内剩余天数,1970平1972闰年
while( Days > 365)
{
if(alg_IsLeapYear(Year))
{
Days--;
}
Days -= 365;
Year++;
}
if (!alg_IsLeapYear(Year) && (Days == 365) )
{
Year++;
LocalTime.my_day =1;
LocalTime.my_month =1;
LocalTime.my_years =Year;
return LocalTime;
}
LocalTime.my_years =Year;
LocalTime.my_month=0;
LocalTime.my_day=0;
if (alg_IsLeapYear(Year)) //本年是闰年
{
for (i = 0; i < 12; i++)
{
if (Days < LeapYearMonth[i])
{
LocalTime.my_month = i + 1;
if (i == 0)
{
LocalTime.my_day = Days;
}
else
{
LocalTime.my_day = Days - LeapYearMonth[i - 1];
}
LocalTime.my_day++;
return LocalTime;
}
}
}
else //本年是平年
{
for (i = 0; i < 12; i++)
{
if (Days < NonleapYearMonth[i])
{
LocalTime.my_month = i + 1;
if (i == 0)
{
LocalTime.my_day = Days;
}
else
{
LocalTime.my_day = Days - NonleapYearMonth[i - 1];
}
LocalTime.my_day++;
return LocalTime;
}
}
}
return LocalTime;
}
unsigned int alg_LocalTime2Utc(my_timejg LocalTime, char TimeZone)
{
unsigned int y = LocalTime.my_years -1970; //看一下有几个400年,几个100年,几个4年
unsigned int dy = (y / 400);
unsigned int days = dy * (400 * 365 + 97); //400年的天数
dy = (y % 400) / 100;
days += dy * (100 * 365 + 25); //100年的天数
dy = (y % 100) / 4;
days += dy * (4 * 365 + 1); //4年的天数
dy = y % 4; //注意:这里1972是闰年,与1970只差2年
days += dy * 365 ;
if(dy == 3) //这个4年里,有没有闰年就差1天
{
days++; //只有这个是要手动加天数的,因为1973年计算时前面的天数按365天算,1972少算了一天
}
if (LocalTime.my_month != 1)
{
if(alg_IsLeapYear(LocalTime.my_years)) //看看今年是闰年还是平年
{
days += LeapYearMonth[(LocalTime.my_month - 1) - 1];
}
else
{
days += NonleapYearMonth[(LocalTime.my_month - 1) - 1]; //如果给定的月份数为x则,只有x-1个整数月
}
}
days += LocalTime.my_day - 1;
return (days * 24 * 3600 + ((unsigned int)LocalTime.my_hour - TimeZone)* 3600 + (unsigned int)LocalTime.my_minutes * 60 + (unsigned int)LocalTime.my_seconds);
}
void my_time_adjust(my_timejg time)
{
rtc_lwoff_wait();
rtc_counter_set(alg_LocalTime2Utc(time,8));
rtc_lwoff_wait();
//PMU 时钟打开
rcu_periph_clock_enable(RCU_BKPI);
rcu_periph_clock_enable(RCU_PMU);
//备份域写使能
pmu_backup_write_enable();
//向备份域写入标记
bkp_data_write(BKP_DATA_0, 0xA5A5);
//备份域写失能
pmu_backup_write_disable();
}
void my_time_read(my_timejg *time)
{
*time=alg_Utc2LocalTime(rtc_counter_get(),8);
}
//重置备份域
static void bkp_deinit(void)
{
/* reset BKP domain register*/
rcu_bkp_reset_enable();
rcu_bkp_reset_disable();
}
void my_rtc_init(void)
{
//PMU 时钟打开
rcu_periph_clock_enable(RCU_BKPI);
rcu_periph_clock_enable(RCU_PMU);
//备份域写使能和重置
pmu_backup_write_enable();
bkp_deinit();
//使能外部32.768晶振
rcu_osci_on(RCU_LXTAL);
//等待外部时钟稳定
rcu_osci_stab_wait(RCU_LXTAL);
//选择外部32.768时钟给RTC供给
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
//使能RTC时钟
rcu_periph_clock_enable(RCU_RTC);
//等待RTC注册同步
rtc_register_sync_wait();
//等待RTC写完数据
rtc_lwoff_wait();
//设置RTC分频器:设置RTC周期为1秒
rtc_prescaler_set(32767);
//等待RTC写完数据
rtc_lwoff_wait();
}
---------------------------------------------------------------------------------------H---------------------------------------------------------------------------------------
#ifndef __MY_RTC__
#define __MY_RTC__
#include "gd32f20x_rtc.h"
#include "gd32f20x_bkp.h"
#include "gd32f20x_rcu.h"
#include "gd32f20x_pmu.h"
#include "stdint.h"
//时间信息结构体
typedef struct
{
unsigned char my_seconds;
unsigned char my_minutes;
unsigned char my_hour;
unsigned char my_day;
unsigned char my_month;
unsigned char my_week;
unsigned int my_years;
}my_timejg;
//设置时间
void my_time_adjust(my_timejg time);
//获取时间
void my_time_read(my_timejg *time);
//UTC时间转换
my_timejg alg_Utc2LocalTime(unsigned int UtcVal, char TimeZone);
//转换为UTC时间
unsigned int alg_LocalTime2Utc(my_timejg LocalTime, char TimeZone);
//同步时间
void my_rtc_sync(void);
//查询是否设置过时间
uint8_t my_rtc_cf(void);
#endif