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。
1. 实现功能
通过内部RTC模块的闹钟事件(对应的是外部中断EXTI 17)来唤醒处于停机模式下的MCU。系统在进入停机模式时拉高GPIO端口,在恢复到正常运行状态时拉低GPIO端口。
2. 配置顺序
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)部分操作要等待写操作完成和同步。
3. 参考代码
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);
}
4. 运行结果
编译软件工程无误后下载代码,调用RTC\_EntryStopMode()函数使系统进入到停机模式,等待RTC闹钟事件3S后唤醒停机模式下的MCU,唤醒后继续执行程序,通过观察GPIO的电平状态来查看运行结果:
用户可以结合上一篇万年历功能设置在某年某月某时某刻定时唤醒MCU功能,万年历的具体实方式可以参考上一篇《MM32F013x——万年历》。