【前言】
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(); } }
【实验效果】