完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
MM32F013x内部的RTC是一个独立的定时器单元,它拥有一组连续计数的计数器,配置相应的寄存器参数,可以实现闹钟、秒中断、毫秒中断、MCU定时唤醒、万年历等功能。 主要特征可编程的预分频系数:分频系数最高为 22032 位的可编程计数器,用于较长时间段的测量2 个分离的时钟:用于 APB1 接口的 PCLK1 和 RTC 时钟 (RTC 时钟的频率必须小于PCLK1 时钟频率的四分之一以上)可以选择以下三种 RTC 的时钟源– HSE 时钟除以 128 – LSE 振荡器时钟 – LSI 振荡器时钟 2 个独立的复位类型 – APB1 接口由系统复位 – RTC 核心 (预分频器、闹钟、计数器和分频器) 只能由后备域复位 3 个专门的屏蔽中断 – 闹钟中断,用来产生一个软件可编程的闹钟中断 – 秒 / 毫秒中断,用来产生一个可编程的周期性中断信号 (最长可达 1 秒) – 溢出中断,指示内部可编程计数器溢出并返回为 0 的状态 本文将重点介绍如何在MM32F013x上通过内部RTC模块实现万年历的功能。 实现功能 通过修改RTC计数器的初始值来设置系统当前的时间和日期,使能RTC秒中断功能;在RTC产生秒中断后,通过获取当前RTC的计数值,将其转换为对应的年月日信息,再通过蔡勒公式计算出星期,将最终的结果通过串口的形式输出显示。 RTC模块的电源域处在VDD数字电源域,只要MCU供电就可以使用RTC,没有独立的VBAT供电引脚,所以无法使用纽扣电池类的应用。 参考代码 01 结构体定义及全局变量 typedef struct { uint16_t year; uint8_t month; uint8_t day; uint8_t week; uint8_t hour; uint8_t minute; uint8_t second; } CALENDAR_t; const uint8_t RTC_DayOfMonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; CALENDAR_t RTC_Calendar; 02 RTC初始化配置:使用外部32.768kHz的晶振源 void RTC_Configure(void) { uint16_t BKP_Value = 0x5A5A; NVIC_InitTypeDef NVIC_InitStructure; /* Enable PWR Clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); /* Enable WKUP pin */ PWR_WakeUpPinCmd(ENABLE); /* Enable Access To The RTC & Backup Registers */ PWR_BackupAccessCmd(ENABLE); if(BKP_ReadBackupRegister(BKP_DR1) != BKP_Value) { BKP_DeInit(); /* Enable LSE Clock Source */ RCC_LSEConfig(RCC_LSE_ON); /* Wait LSI Clock Source Ready */ while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); /* Config RTC Clock Source : LSE */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); /* Enable RTC Clock */ RCC_RTCCLKCmd(ENABLE); /* Wait For Synchronization */ RTC_WaitForSynchro(); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); /* Set The RTC Prescaler Value */ RTC_SetPrescaler(32767); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); /* Enable RTC Second Interrupt */ RTC_ITConfig(RTC_IT_SEC, ENABLE); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); /* Exit From The RTC Configuration Mode */ RTC_ExitConfigMode(); BKP_WriteBackupRegister(BKP_DR1, BKP_Value); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); /* Set initial time */ RTC_SetDateTime(2021, 1, 12, 14, 48, 0); } else { /* Wait For Synchronization */ RTC_WaitForSynchro(); /* Enable RTC Second Interrupt */ RTC_ITConfig(RTC_IT_SEC, ENABLE); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); } /* Config RTC NVIC */ NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } 03 RTC秒中断函数 void RTC_BKP_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_SEC) != RESET) { /* Update Date and Time */ RTC_UpdateCalendar(); /* Print current Date and Time */ RTC_PrintDateTime(); /* Clear AlARM Flag */ RTC_ClearITPendingBit(RTC_IT_SEC); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); } } 04 将RTC计数值转换为日期信息 void RTC_UpdateCalendar(void) { static uint32_t PreTotalDay = 0; uint32_t TotalSecond = 0; uint32_t TotalDay = 0; uint16_t Year = 1970; uint8_t Month = 0; /* Get The RTC Counter Value */ TotalSecond = RTC_GetCounter(); TotalDay = TotalSecond / 86400; if(PreTotalDay != TotalDay) { PreTotalDay = TotalDay; while(TotalDay >= 365) { if(RTC_LeapYear(Year) == 1) { if(TotalDay >= 366) { TotalDay -= 366; } else { break; } } else { TotalDay -= 365; } Year++; } RTC_Calendar.year = Year; while(TotalDay >= 28) { if((Month == 1) && (RTC_LeapYear(RTC_Calendar.year) == 1)) { if(TotalDay >= 29) { TotalDay -= 29; } else { break; } } else { if(TotalDay >= RTC_DayOfMonth[Month]) { TotalDay -= RTC_DayOfMonth[Month]; } else { break; } } Month++; } RTC_Calendar.month = Month + 1; RTC_Calendar.day = TotalDay + 1; RTC_Calendar.week = RTC_GetWeek(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day); } RTC_Calendar.hour = (TotalSecond % 86400) / 3600; RTC_Calendar.minute = ((TotalSecond % 86400) % 3600) / 60; RTC_Calendar.second = ((TotalSecond % 86400) % 3600) % 60; } 05 将日期信息转换为RTC计数值 void RTC_SetDateTime(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Min, uint8_t Sec) { uint32_t TotalSecond = 0; uint16_t y = 0; uint8_t m = 0; if((Year >= 1970) && (Year <= 2099)) { for(y = 1970; y < Year; y++) { if(RTC_LeapYear(y) == 1) { TotalSecond += 31622400; /* Total Seconds Of Leap Year */ } else { TotalSecond += 31536000; /* Total Seconds Of Normal Year */ } } for(m = 0; m < (Month - 1); m++) { TotalSecond += RTC_DayOfMonth[m] * 86400; /*Total Seconds Of Month */ if((RTC_LeapYear(Year) == 1) && (m == 1)) { TotalSecond += 86400; } } TotalSecond += (uint32_t)(Day - 1) * 86400; /* Total Seconds Of Day */ TotalSecond += (uint32_t)Hour * 3600; /* Total Seconds Of Hour */ TotalSecond += (uint32_t)Min * 60; /* Total Seconds Of Minute */ TotalSecond += Sec; /* Enable PWR Clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); /* Enable Access To The RTC & Backup Registers */ PWR_BackupAccessCmd(ENABLE); /* Set The RTC Counter Value */ RTC_SetCounter(TotalSecond); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); RTC_UpdateCalendar(); } else { printf("rnError Date & Time!!!rn"); } } 06 RTC信息打印 void RTC_PrintDateTime(void) { printf("rn%04d-%02d-%02d", RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day); switch(RTC_Calendar.week) { case 0 : printf(" SUN "); break; case 1 : printf(" MON "); break; case 2 : printf(" TUE "); break; case 3 : printf(" WED "); break; case 4 : printf(" THU "); break; case 5 : printf(" FRI "); break; case 6 : printf(" SAT "); break; default: break; } printf("%02d:%02d:%02drn", RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second); } 07 RTC功能函数:判断闰年、蔡勒公式计算星期 uint8_t RTC_LeapYear(uint16_t Year) { if( (((Year % 400) == 0) ) || /* Century Leap Year */ (((Year % 100) != 0) && ((Year % 4) == 0)) /* Normal Leay Year */ ) { return 1; } else { return 0; } } uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day) { int w, c, y; /* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */ if((Month == 1) || (Month == 2)) { Month += 12; Year -= 1; } w = 0; /* Weekday */ c = Year / 100; /* Century */ y = Year % 100; /* Year */ w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1; while(w < 0) w += 7; w %= 7; return w; } 运行结果 编译软件工程无误后下载代码,在串口终端工具中我们可以看到每间隔1秒钟,RTC产生一次中断,在中断中我们将当前的日期信息通过串口打印在显示终端软件上: |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2249个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11703 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5930 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10965 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4577 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4302 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
981浏览 1评论
806浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 22:15 , Processed in 0.617506 second(s), Total 64, Slave 48 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号