【前言】
MAX32625拥有RTC外设,实时时钟(RTC)的设计使其在很大程度上独立于设备上的其他数字和模拟功能运行。RTC有自己的专用时钟,rclk4096,它来源于ck32768(32.768KHz晶体振荡器输出或外部提供的32.768kHz时钟)。RTC始终从VRTC专用的备用电源运行,即使在最低功率状态LPO:STOP期间,该电源也打算保持开启。RTC消耗的功率非常小,并使用一个专用的低功耗时钟源。因此,当MAX32625的其他部分处干最低功耗模式LPO:STOP时,RTC仍然可以继续运行RTC可以用干存预定的时间间隔后自动从LPO:STOP或LP1:STANDBY唤醒设备。它还可以用干保持一个稳定的计时器,即使在系统其他部分断电或完全断电的情况下,计时器也能继续正确计数时间。只要备用电源VRtc存在,实时时钟就可以继续正常操作。
这一篇将简单的配置RTC实现设置时间与读取,通过OLED显示。
1、引入rtc的驱动库:

2、由于RTC的时间是一个uint32_t的数值,RTC通过设置后,每单位时间对其进行加,因此我们需要设置一个相对的时间,然后再通过计算来获取时间。因此我添加了一个rtc_api.h/c的文件,实现对时间参数进行解析与打包:
#include "rtc_api.h"
#include <stdint.h>
const uint8_t mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
#define RTC_TIME_START_YEAR (2000)
/**********************************************
* 函数名 : RTC_IsLeapYear
* 描 述 : 判断是否是闰年
* 输 入 : uint16_t year 当前的年份
* 输 出 : None
* 返回值 : 1 闰年 0 非闰年
**********************************************/
uint8_t RTC_IsLeapYear(uint16_t year)
{
if(year%4==0)
{
if(year%100==0)
{
if(year%400==0)
return 1;
else
return 0;
}
else
{
return 1;
}
}
else
{
return 0;
}
}
/**********************************************
* 函数名 : RTC_GetDate
* 描 述 : 将2000年以后秒数转换为年月日时分秒
* 输 入 : uint32_t timecount 2000年以后的秒数
* 输 出 : 当前的年月日时分秒
* 返回值 : 0,成功;其他:错误代码.
**********************************************/
uint8_t RTC_GetDate(uint32_t timecount, uint16_t * year, uint8_t *mon, uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec)
{
uint64_t temp=0;
uint16_t temp1=0;
temp=timecount/86400; //得到天数(秒钟数对应的)
temp1=2000; //从1970年开始
while(temp>=365)
{
if(RTC_IsLeapYear(temp1))//是闰年
{
if(temp>=366)temp-=366;//闰年的秒钟数
else {temp1++;break;}
}
else temp-=365; //平年
temp1++;
if(temp1 > 2099)
return 2;//大于2099年,退出
}
*year = temp1;//得到年份
temp1=0;
while(temp>=28)//超过了一个月
{
if(RTC_IsLeapYear(*year)&&temp1==1)//当年是不是闰年/2月份
{
if(temp>=29)temp-=29;//闰年的秒钟数
else break;
}
else
{
if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
else break;
}
temp1++;
}
*mon=temp1+1; //得到月份
*day=temp+1; //得到日期
temp=timecount%86400; //得到秒钟数
*hour=temp/3600; //小时
*min=(temp%3600)/60; //分钟
*sec=(temp%3600)%60; //秒钟
return 0;
}
/**********************************************
* 函数名 : RTC_GetSecFrom2000
* 描 述 : 得到2000年以后的秒数
* 输 入 : 当前的年月日时分秒
* 输 出 : None
* 返回值 : 2000年以后的秒数
**********************************************/
uint32_t RTC_GetSecFrom2000(uint16_t year,uint8_t month,uint8_t day,uint8_t hour,uint8_t min, uint8_t sec)
{
uint32_t seccount = 0;//一定要初始化
uint16_t t;
if(year < RTC_TIME_START_YEAR || year > 2099)
return 0;
for(t= RTC_TIME_START_YEAR;t<year;t++)
{
if(RTC_IsLeapYear(t))
seccount += 31622400;
else
seccount += 31536000;
}
month-=1;
for(t=0;t<month;t++)
{
seccount += (uint32_t)mon_table[t]*86400;
if(RTC_IsLeapYear(year)&&t==1)
seccount+=86400;
}
seccount += (uint32_t)(day-1)*86400;
seccount += (uint32_t)hour*3600;
seccount += (uint32_t)min*60; //分钟秒钟数
seccount += sec;
return seccount;
}3、在main.c中添加配置函数:
#define ALARM0_SEC 3
#define ALARM1_SEC 5
#define SNOOZE_SEC 7
void RTC_Setup()
{
timesecond = RTC_GetSecFrom2000(2025,5,11,17,39,1);
rtc_cfg_t RTCconfig;
//set RTC configuration
RTCconfig.compareCount[0] = ALARM0_SEC; //alarm0 time in seconds
RTCconfig.compareCount[1] = ALARM1_SEC; //alarm1 time in seconds
RTCconfig.prescaler = RTC_PRESCALE_DIV_2_12; //1Hz clock
RTCconfig.prescalerMask = RTC_PRESCALE_DIV_2_11;//0.5s prescaler compare
RTCconfig.snoozeCount = SNOOZE_SEC;//snooze time in seconds
RTCconfig.snoozeMode = RTC_SNOOZE_MODE_B;
RTC_Init(&RTCconfig);
RTC_Init(&RTCconfig);
RTC_Stop();
RTC_SetCount(timesecond);
//start RTC
RTC_Start();
}4、在main中通过周期读取实现RTC的时间显示:
int main(void)
{
char buff[40] = {0};
GPIO_Config(&LED1);
OLED_Init();
OLED_Clear(0);
GUI_ShowString(0,0,"hello world",16,0);
OLED_Display();
RTC_Setup();
while (1)
{
OLED_Clear(0);
timesecond = RTC_GetCount();
RTC_GetDate(timesecond, &year, &mon, &day, &hour, &min, &sec);
sprintf(buff, "Time:%02d:%02d:%02d\n", hour, min, sec);
GUI_ShowString(0,16,buff,16,0);
OLED_Display();
GPIO_OutToggle(&LED1);
pause();
}
}【实验效果】

我要赚赏金
