1MM32L0130 RTC简介
RTC 模块是用于提供时间(时、分、秒、亚秒)和日期(年、月、日)功能的定时计数器,日历以 BCD码的格式显示。内部包含周期性的唤醒单元,用于唤醒低功耗模式。支持夏令时补偿,支持数字校准补偿晶振精度的偏差。灵动微电子推出的MM32L0130系列MCU片上RTC外设具有以下特征:
可编程的日历功能,包括时、分、秒、小时(12/24 小时制)、日期、星期、月份、年份
软件可编程的夏令时补偿
可编程闹钟,任意日历字段的组合触发闹钟
周期性自动唤醒单元,唤醒时间可配置
数字校准,精度为 0.95ppm
通过移位功能调整亚秒时间
支持可配置的时间戳功能,用于记录事件的入侵时间
支持可配置的入侵检测
5 个 32 位宽的备份数据寄存器,当发生入侵事件时会复位备份数据寄存器
可屏蔽中断源
• 闹钟
• 唤醒单元
• 时间戳事件
• 入侵事件
2RTC功能描述
2.1 RTC模块系统框图
RTC中断请求:
注:
当使用了 PC13 的时间戳或入侵的功能时,如果需要使用 PC13 用做复用功能或者输出时,需要关闭时间戳或入侵对应的寄存器的使能位释放 PC13。
RTC_ALARM 为闹钟或唤醒标志输出, RTC_CALB 代表校准时钟输出,最终会输出到 PAD,具体的复用关系参考芯片数据手册与 RTC_OR 输出控制寄存器。
TAMP_IN 代表外部入侵管脚, TIM_TS 代表时间戳管脚,具体的对应关系参考芯片数据手册部分。
2.2 时钟和预分频
RTC 时钟包含3个独立可配置的时钟源:分别是 LSE、 LSI、 HSE 时钟的 128 分频。RTC 内部包含2个预分频器用于提供日历或其它功能的时钟,分别是一个 7 位的异步预分频器与15位的同步预分频器,为了降低功耗,建议将异步预分频的值设置到可能的最大值。
异步分频器输出时钟为fck_apre;同步预分频器输出时钟为fck_spre。
计算公式如下:
fck_apre时钟用于为二进制格式的 RTC_SSR 亚秒递减计数器提供时钟。当该递减计数器计数到 0 时,会使用 PREDIV_S 的内容重载 RTC_SSR, fck_spre用于为日历计数单元提供时钟。
注:
针对 32.768KHZ 的 LSE 时钟,异步分频部分默认设置为 128,同步分频部分设置为 256,产生1HZ(fck_spre)的时钟用于日历计数。
2.3 实时时钟和日历
RTC 时间和日期寄存器对应如下:
RTC_SSR 对应于亚秒
RTC_TR 对应于时间
RTC_DR 对应于日期
通过 APB 总线访问日历时间与日期寄存器时,由 RTC_CR 寄存器中的 BYPSHAD 位决定访问实时的日历寄存器还是影子寄存器,默认情况下访问的是影子寄存器。
每隔 2 个 RTC 时钟周期,会将实时的日历寄存器复制到影子寄存器,并将 RTC_ISR 寄存器的 RSF位置 1,在停机和待机模式下不会执行复制操作。退出这两种模式时,影子寄存器会在最长 2 个 RTC 时钟周期后进行更新。影子寄存器可以通过系统复位复位。
2.4 可编程闹钟
RTC 闹钟单元被划分为多个位 ,并且每个位支持独立的使能或屏蔽。具体可以通过配置RTC_ALRMAR 寄存器 MSKx 位以及 RTC_ALRMASSR 寄存器的 MASKSSx 位。
配置 RTC_CR 寄存器中的 ALRAE 位使能可编程闹钟功能。当该位为 1,并且配置的 RTC_ALRMAR寄存器的值同当前日历一致时, RTC_ISR 寄存器中的 ALRAF 位会置 1。同时配置 RTC_CR 寄存器中的ALRAIE 位等于 1 时,会产生闹钟中断输出。
配置 RTC_CR 寄存器中的位 OSEL[1:0]等于 1, ALRAF 连接到 RTC_ALARM 输出,配置 RTC_CR寄存器的 POL 位选择 RTC_ALARM 输出极性。
MM32L0130的RTC外设还有周期唤醒单元、日历读取、复位RTC、RTC数字校准、RTC移位、时间戳、入侵检测、RTC低功耗唤醒等功能, 在用户手册RTC章节有进行详细描述,大家可以参考查阅,此处不再进行赘述,实验涉及到再进行说明。
3实验
3.1 实验原理
RTC 闹钟单元被划分为多个位,包括日期、星期、小时、分钟、秒,并且每个位支持独立的使能或屏蔽。当配置的闹钟A寄存器的值与当前日历(时间/日期)寄存器的值一致时,闹钟发生,相应标志置位。如果使能了闹钟中断,则会产生闹钟中断输出。
配置时间寄存器、日期寄存器的值来初始化日历,配置闹钟A寄存器的值,并使能闹钟中断,每次闹钟A寄存器的值与当前时间/日期寄存器的值一致时,闹钟发生,产生闹钟中断。读取日历,如果查询到闹钟发生,串口打印闹钟发生次数与当前日历数据。
在日历的基础上实现闹钟功能,为便于观察和验证,实验中配置闹钟发生的时间尽可能短,匹配到秒而将其余位屏蔽以使闹钟发生。
3.2 程序设计
3.21 RTCCAL_Initialize() 函数
函数实现日历初始化配置,按如下步骤初始化日历时间与日期寄存器:
1配置 RTC_ISR 寄存器中的 INIT 位为 1 以进入初始化模式
2等待 RTC_ISR 寄存器中的 INITF 位被硬件置 1
3编程 RTC_PRER 寄存器,配置同步与异步预分频系数
4配置影子寄存器(RTC_TR 和 RTC_DR),加载日历初值,配置 RTC_CR 寄存器中的 FMT 位选择 12 或 24 小时制
5清除 RTC_ISR 寄存器中的 INIT 位退出初始化模式
注:
约 4 个 RTC 时钟周期后,影子寄存器配置值加载到内部实时计数器。初始化影子寄存器后,等待 RTC_ISR 寄存器的 RSF 位置 1,才能读取日历。
void RTCCAL_Initialize(void) { //Check if the clock is configured for the first time RTCCAL_InitTypeDef init_struct; RTCCAL_TimeTypeDef setTimeStruct; RTCCAL_DateTypeDef setDateStruct; u16 temp = 0; RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR, ENABLE); //(1) RCC_APB1PeriphClockCmd(RCC_APB1ENR_BKP, ENABLE); //(2) PWR_BackupAccessCmd(ENABLE); //(3) RCC_LSEConfig(RCC_LSE_ON); delay_x_cycle(2000); //Check whether the specified RCC marker is set or not, and wait for the //low-speed crystal oscillator to be ready while(1) { if(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != RESET) { //(4) break; } temp++; if(temp >= LSE_READY_TIMEOUT) { while(1) { __NOP(); } } delay_x_cycle(10); } RCC_APB1PeriphClockCmd(RCC_APB1ENR_RTC, ENABLE); //Setting RTC Clock RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTCCAL_EnterInitMode(); //(5) RTCCAL_WaitForSynchro(); RTCCAL_StructInit(&init_struct); init_struct.RTCCAL_AsynchPrediv = 0x7F; //(6) init_struct.RTCCAL_SynchPrediv = 0xFF; init_struct.RTCCAL_HourFormat = RTCCAL_HourFormat_24; RTCCAL_Init(&init_struct); RTCCAL_TimeStructInit(&setTimeStruct); setTimeStruct.RTCCAL_H12 = RTCCAL_H12_AM; //(7) setTimeStruct.RTCCAL_Hours = 15; setTimeStruct.RTCCAL_Minutes = 34; setTimeStruct.RTCCAL_Seconds = 0; RTCCAL_SetTime(RTCCAL_Format_BCD, &setTimeStruct); RTCCAL_DateStructInit(&setDateStruct); setDateStruct.RTCCAL_Year = 0x16; //(8) setDateStruct.RTCCAL_Month = 0x0A; setDateStruct.RTCCAL_Date = 0x1A; setDateStruct.RTCCAL_WeekDay = 0x01; RTCCAL_SetDate(RTCCAL_Format_BCD, &setDateStruct); RTCCAL_WaitForSynchro(); RTCCAL_ExitInitMode(); //(9) }
(1)、(2)配置 RTC 需要使能 PWR 和 BKP 的时钟
(3)RTC 寄存器写保护,取消备份域的写保护
(4)等待 LSE 时钟稳定,选择 LSE 作为 RTC 时钟源
(5)确认 RTC 进入初始化模式
(6)配置 RTC 预分频寄存器,时钟频率为 1HZ
(7)配置 PTC_TR时间寄存器,更新时间
(8)配置 PTC_DR日期寄存器,更新日期
(9)RTC 退出初始化模式
3.22 RTCCAL_AlarmConfig() 函数
函数实现闹钟初始化配置,按如下步骤编程闹钟:
1配置 RTC_CR 中的 ALRAE 位等于 0 禁止闹钟 A
2等待 RTC_ISR 寄存器中的 ALRAWF 位等于 1
3设置闹钟寄存器(RTC_ALRMASSR/RTC_ALRMAR)
4配置 RTC_CR 寄存器中的 ALRAE 位等于 1 使能闹钟 A
注:
对 RTC_CR 寄存器执行的写操作。约 2 个 RTC 时钟周期同步后生效。
void RTCCAL_AlarmConfig(void) { RTCCAL_AlarmTypeDef RTCCAL_AlarmStructure; RTCCAL_NVIC_Config(); //(1) // Set the alarm A Masks RTCCAL_AlarmStructure.RTCCAL_AlarmMask = (RTCCAL_ALRMAR_MSK4 | RTCCAL_ALRMAR_MSK3 | RTCCAL_ALRMAR_MSK2); //(2) RTCCAL_AlarmStructure.RTCCAL_AlarmDateWeekDaySel = RTCCAL_AlarmDateWeekDaySel_Date; RTCCAL_AlarmStructure.RTCCAL_AlarmDateWeekDay = RTCCAL_Weekday_Monday; RTCCAL_AlarmStructure.RTCCAL_AlarmTime.RTCCAL_Hours = 0; RTCCAL_AlarmStructure.RTCCAL_AlarmTime.RTCCAL_Minutes = 0; RTCCAL_AlarmStructure.RTCCAL_AlarmTime.RTCCAL_Seconds = 9; if(ERROR == RTCCAL_AlarmCmd(RTCCAL_Alarm_A, DISABLE)) { while(1) {}; } RTCCAL_SetAlarm(RTCCAL_Format_BCD,RTCCAL_Alarm_A, &RTCCAL_AlarmStructure); RTCCAL_AlarmSubSecondConfig(RTCCAL_Alarm_A, 0xFF, RTCCAL_AlarmSubSecondMask_SS14_5); //(3) // Enable alarm A interrupt RTCCAL_ITConfig(RTCCAL_IT_ALRA, ENABLE); //(4) if(ERROR == RTCCAL_AlarmCmd(RTCCAL_Alarm_A, ENABLE)) { while(1) {}; } }
(1)配置RTC闹钟中断,RTC&BKP全局中断连接到 EXTI17
(2)配置闹钟A寄存器,屏蔽日期/星期、时、分,仅匹配秒
(3)配置闹钟A亚秒寄存器
(4)使能闹钟A中断
3.23 RTC_BKP_IRQHandler() 函数
RTC闹钟中断服务子程序,记录闹钟中断次数,置位标志位。
void RTC_BKP_IRQHandler(void ) { if(RTCCAL_GetITStatus(RTCCAL_IT_ALRA) != RESET) { RTCCAL_ClearITPendingBit(RTCCAL_IT_ALRA); Flag_ALARM = 1; if(AlarmCount > 500) { RCC_RTCCLKCmd(DISABLE); AlarmCount = 0; } else { AlarmCount++; } EXTI_ClearITPendingBit(EXTI_Line17); } }
3.24 main() 函数
函数实现各模块初始化,在循环中获取当前日期、时间,查询到闹钟发生,打印当前日期、时间。
s32 main(void) { RTCCAL_DateTypeDef RTCCAL_tempDate; RTCCAL_TimeTypeDef RTCCAL_tempTime; DELAY_Init(); CONSOLE_Init(115200); RTCCAL_LSE_DemoInit(); while(1) { if(Flag_ALARM == 1) { Flag_ALARM = 0; printf("Alarm clock was triggered %d times ! ", AlarmCount); printf("20"); printf("%02d-",RTCCAL_tempDate.RTCCAL_Year); printf("%02d-",RTCCAL_tempDate.RTCCAL_Month); printf("%02d ",RTCCAL_tempDate.RTCCAL_Date); printf("%02d:",RTCCAL_tempTime.RTCCAL_Hours); printf("%02d:",RTCCAL_tempTime.RTCCAL_Minutes); printf("%02d ",RTCCAL_tempTime.RTCCAL_Seconds); printf(" "); } } }
3.3 实验演示
下载程序运行,观察串口调试助手:
串口调试助手间隔打印数据,比较前后两次数据的日期和时间,相差1分钟,在每分钟的第9秒闹钟发生,和闹钟寄存器配置一致,运行情况和预期设计相符。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !