RTC可用于周期性从低功耗模式下唤醒MCU,RTC可选三个时钟源:
- 低功耗 32.768kHz 外部低速晶振 (LSE):该时钟源提供了一个低功耗且精确的时间基准。
- 低功耗内部低速振荡器 (LSI):使用该时钟源,节省了一个 32.768kHz 晶振的成本,但是精度没有外部晶振的精度高。
- 外部高速晶振(HSE)128分频:在某些低功耗模式中HSE被关闭会导致RTC无时钟源。
为了用 RTC 闹钟事件将系统从停机模式下唤醒,必须进行如下操作:
- 配置外部中断线 17 为上升沿触发。
- 配置 RTC 使其可产生 RTC 闹钟事件。
如果要从待机模式中唤醒, 不必配置外部中断线 17。
MM32F013x有三种低功耗模式:睡眠模式(Sleep Mode)、停机模式(Stop Mode)和待机模式(Standby Mode),三种低功耗模式的对比如下表所示:
从上表中可以看出,当MCU工作在停机模式时,可以通过任一外部中断事件来唤醒。MM32F013x低功耗模式下的功耗列表如下图所示:
MM32F013x有22个外部中断源,其中EXTI 17对应的是RTC闹钟事件,所以结合RTC闹钟的功能,本文将重点介绍如何在MM32F013x上通过内部RTC模块的闹钟事件来唤醒处于停机模式下的MCU。
01、实现功能
通过内部RTC模块的闹钟事件(对应的是外部中断EXTI 17)来唤醒处于停机模式下的MCU。系统在进入停机模式时拉高GPIO端口,在恢复到正常运行状态时拉低GPIO端口。
02、配置顺序
1)使能PWR和BKP时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
2)使能后备寄存器访问:
PWR_BackupAccessCmd(ENABLE);
3)配置RTC时钟源,使能RTC时钟,如果使用LSE,要打开LSE:
RCC_LSEConfig(RCC_LSE_ON); while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE);
4)设置RTC预分频系数:
RTC_SetPrescaler();
5)开启相关中断:
RTC_ITConfig(RTC_IT_ALR, ENABLE);
6)配置外部中断线:
EXTI_StructInit(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure);
7)配置中断服务函数:
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
8)部分操作要等待写操作完成和同步。
03、参考代码
3.1 RTC初始化配置:使用外部32.768kHz的晶振源
void RTC_Configure(void) { uint16_t BKP_Value = 0x5A5A; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* Enable PWR Clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, 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 Alarm Interrupt */ RTC_ITConfig(RTC_IT_ALR, 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(); } else { /* Wait For Synchronization */ RTC_WaitForSynchro(); /* Enable RTC Alarm Interrupt */ RTC_ITConfig(RTC_IT_ALR, ENABLE); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); } /* Clear EXTI Line17 Flag */ EXTI_ClearITPendingBit(EXTI_Line17); /* Configure EXTI Line17(RTC Alarm) To Generate An Interrupt On Rising Edge */ EXTI_StructInit(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* Config RTC NVIC */ NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
3.2 RTC闹钟中断函数
void RTC_BKP_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_ALR) != RESET) { GPIO_WriteBit(LED_GPIO, LED_PIN, Bit_RESET); /* Clear EXTI Line17 Flag */ EXTI_ClearITPendingBit(EXTI_Line17); /* Check If The Wake-Up Flag Is Set */ if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET) { /* Clear Wake Up Flag */ PWR_ClearFlag(PWR_FLAG_WU); } /* Clear Alarm Flag */ RTC_ClearITPendingBit(RTC_IT_ALR); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); } }
3.3 设置RTC闹钟时间,系统进入STOP模式
void RTC_EntryStopMode(void) { /* Wait till RTC Second event occurs */ RTC_ClearFlag(RTC_FLAG_SEC); while(RTC_GetFlagStatus(RTC_FLAG_SEC) == RESET); /* Set The RTC Alarm Value */ RTC_SetAlarm(RTC_GetCounter() + 3); /* Wait Until Last Write Operation On RTC REG Has Finished */ RTC_WaitForLastTask(); GPIO_WriteBit(LED_GPIO, LED_PIN, Bit_SET); /* Enter Stop Mode */ PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); }
04、运行结果
编译软件工程无误后下载代码,调用RTC_EntryStopMode()函数使系统进入到停机模式,等待RTC闹钟事件3S后唤醒停机模式下的MCU,唤醒后继续执行程序,通过观察GPIO的电平状态来查看运行结果:
用户可以结合上一篇万年历功能设置在某年某月某时某刻定时唤醒MCU功能,万年历的具体实方式可以参考上一篇《MM32F013x——万年历》。
转自:灵动微电子