打印
[APM32F4]

APM32F402实现RTC定时唤醒STOP模式

[复制链接]
281|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

APM32F402实现RTC定时唤醒STOP模式

申请原创# @21小跑堂

低功耗模式

按功耗由高到低排列,APM32F402具有运行、睡眠、停止和待机四种工作模式。上电复位后APM32F402处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式降低功耗,这三种模式中,功耗消耗不同、唤醒时间不同、唤醒源不同,用户需要根据应用需求,选择最佳的低功耗模式;三种低功耗的模式说明见下表。

image.png

image.png

SLEEP模式

SLEEP模式又叫睡眠模式,在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,内核的外设全都还照常运行。睡眠模式有两种方式进入睡眠模式, 它的进入方式也决定了从睡眠模式唤醒的方式,分别是WFI(等待中断)和WFE(等待事件);睡眠模式的各种特性见下表。

image.png

在APM32F402中我们可以通过PMU_EnterSleepMode函数来进入睡眠模式,其参数PMU_SLEEPENTRY_WFI和PMU_SLEEPENTRY_WFE决定我们怎么进入和唤醒睡眠模式,分别代表中断和事件。

STOP模式

STOP模式又叫停止模式,在停止模式中,在睡眠模式的基础上进一步关闭了其它所有的时钟,因此其所有的外设都停止了工作,但由于其1.2V区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断(EINT)唤醒,在停止模式中可以选择电压调节器为正常模式或低功耗模式;停止模式的各种特性见下表。

image.png

image.png

在APM32F402中我们可以通过PMU_EnterSTOPMode函数来进入停止模式,其参数1决定调压器处于正常模式(PMU_REGULATOR_ON)还是低功耗模式(PMU_REGULATOR_LOWPOWER),其参数2决定是中断进入停止模式还是事件进入停止模式,分别是PMU_STOP_ENTRY_WFI&PMU_STOP_ENTRY_WFE。

STANDBY模式

STANDBY模式又叫待机模式,待机模式除了关闭所有的时钟,还把1.2V区域的电源也完全关闭了,也就是说,从待机模式唤醒后,没有之前代码的运行记录,只能对芯片复位,重新检测boot条件,从头开始执行程序。它有四种唤醒方式,分别是WKUP(PA0)引脚的上升沿,RTC闹钟事件,NRST引脚的复位和IWDG(独立看门狗)复位;待机模式的各种特性见下表。

image.png

RTC实现定时唤醒停止模式

上面的停止模式中描述有说,停止模式可以通过任意中断唤醒,当然前提是中断进入的停止模式哈,在EINT章节中我们可以看到RTC Alarm 事件映射到EINT 17线,那么我们也可以通过RTC闹钟来实现定时唤醒停止模式。

RTC闹钟配置

在RTC闹钟配置中,我们使用内部的LSI配置为RTC时钟源,配置5s的闹钟,并且把RTC Alarm和EINT 17想关联起来

void RTC_Config_Init(void)
{
    EINT_Config_T EINT_Configure;

    /* 使能BKP和PWR时钟 */
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR);
    /* 允许访问备份域 */
    PMU_EnableBackupAccess();
    /* 备份域复位 */
    BAKPR_Reset();

    /* 使能LSI */
    RCM_EnableLSI();
    /* 等待直到LSI就绪 */
    while(RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
    /* 选择LSI作为RTC时钟源 */
    RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
    /* 使能RTC时钟 */
    RCM_EnableRTCCLK();

    /* 等待RTC寄存器同步 */
    RTC_WaitForSynchro();
    /* 等待RTC寄存器上的最后一次写操作完成 */
    RTC_WaitForLastTask();
    /* 使能RTC闹钟中断 */
    RTC_EnableInterrupt(RTC_INT_ALR);
    /* 等待RTC寄存器上的最后一次写操作完成 */
    RTC_WaitForLastTask();
    /* 设置RTC分频值: 设置RTC周期为1s */
    RTC_ConfigPrescaler(40000);
    /* 等待RTC寄存器上的最后一次写操作完成 */
    RTC_WaitForLastTask();
    /* 设置RTC计数器值为0 */
    RTC_ConfigCounter(0U);
    /* 等待RTC寄存器上的最后一次写操作完成 */
    RTC_WaitForLastTask();
    /* 设置RTC闹钟值为5s */
    RTC_ConfigAlarm(ALARM_TIME_INTERVAL);
    /* 等待RTC寄存器上的最后一次写操作完成 */
    RTC_WaitForLastTask();

    /* EXTI配置 */
    EINT_Reset();
    EINT_Configure.line = EINT_LINE_17;
    EINT_Configure.lineCmd = ENABLE;
    EINT_Configure.mode = EINT_MODE_INTERRUPT;
    EINT_Configure.trigger = EINT_TRIGGER_RISING;
    EINT_Config(&EINT_Configure);

    /* 标志清除 */
    RTC_ClearStatusFlag(RTC_FLAG_ALR);
    EINT_ClearIntFlag(EINT_LINE_17);

    /* NVIC配置 */
    NVIC_EnableIRQRequest(RTC_Alarm_IRQn, 1, 1);
}

RTC闹钟中断配置

在RTC闹钟中断服务函数,我们检测到RTC闹钟中断,先清除闹钟标志和EINT 17的标志,然后我们在重新设置RTC的计数器的值和闹钟值,实现再配置5sRTC闹钟

void RTC_Alarm_IRQHandler(void)
{
    if(RTC_ReadIntFlag(RTC_INT_ALR) == SET)
    {
        /* 清除RTC闹钟和EXTI_Line17中断标志 */
        RTC_ClearIntFlag(RTC_INT_ALR);
        EINT_ClearIntFlag(EINT_LINE_17);
        /* 等待RTC寄存器同步 */
        RTC_WaitForSynchro();
        /* 等待RTC寄存器上的最后一次写操作完成 */
        RTC_WaitForLastTask();
        /* 设置RTC计数器值为0 */
        RTC_ConfigCounter(0U);

        /* 等待RTC寄存器上的最后一次写操作完成 */
        RTC_WaitForLastTask();
        /* 设置RTC闹钟值为5s */
        RTC_ConfigAlarm(ALARM_TIME_INTERVAL);
        /* 等待RTC寄存器上的最后一次写操作完成 */
        RTC_WaitForLastTask();

    }
}

进入STOP模式前IO的配置

进入停止模式前把所有未使用的IO配置模拟输入,这样子功耗可以到达最低。

void GPIO_ALL_Init(void)
{
    GPIO_Config_T GPIO_Configure;

    /* 使能所有GPIO时钟 */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOB | RCM_APB2_PERIPH_GPIOC | RCM_APB2_PERIPH_GPIOD);

    /* IO配置模拟输入,为了达到STOP模式功耗最低,保留PA0中断唤醒 */
    GPIO_Configure.mode = GPIO_MODE_ANALOG;
    GPIO_Configure.pin = GPIO_PIN_ALL&(~GPIO_PIN_0);
    GPIO_Config(GPIOA, &GPIO_Configure);

    GPIO_Configure.pin = GPIO_PIN_ALL;
    GPIO_Config(GPIOB, &GPIO_Configure);
    GPIO_Config(GPIOC, &GPIO_Configure);
    GPIO_Config(GPIOD, &GPIO_Configure);

    /* 失能所有GPIO时钟 */
    RCM_DisableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOB | RCM_APB2_PERIPH_GPIOC | RCM_APB2_PERIPH_GPIOD);
}

进入停止模式

void System_Enter_StopMode(void)
{
    /* 使能PWR时钟 */
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
    /* 清除唤醒标志 */
    PMU_ClearStatusFlag(PMU_FLAG_WUE);
    /* 进入Stop模式 */
    PMU_EnterSTOPMode(PMU_REGULATOR_LOWPOWER, PMU_STOP_ENTRY_WFI);
}

RTC闹钟定时唤醒STOP模式验证

在主函数里面实现延时5s后进入STOP模式,然后RTC闹钟5s之后就会再唤醒MCU,然后在重新配置主频和其他外设,最后进入while循环。

//RTC闹钟值的宏
#define ALARM_TIME_INTERVAL  (5U)

void System_Enter_StopMode(void);
void GPIO_ALL_Init(void);
void RTC_Config_Init(void);


int main(void)
{
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_2);

    BSP_HSI64_SysclkConfig();
    BSP_Systick_Init(64);
    BSP_LED_Init(GPIOB, GPIO_PIN_8);
    BSP_LED_Init(GPIOB, GPIO_PIN_9);
    BSP_KEY2_Init(BUTTON_MODE_EXTI);
    BSP_USART1_Init(115200);

    printf("SYSCLKFreq = %d\r\n", RCM_ReadSYSCLKFreq());

    //延时5s再进入Standby模式,方便复位的时候擦除和重新下载程序
    delay_ms(1000);
    delay_ms(1000);
    delay_ms(1000);
    delay_ms(1000);
    delay_ms(1000);
    printf("After a 5-second delay, enter Stop mode\r\n");
    GPIO_ALL_Init();
    RTC_Config_Init();
    System_Enter_StopMode();

    //唤醒需要重新配置时钟
    BSP_HSI64_SysclkConfig();
    BSP_Systick_Init(64);
    BSP_LED_Init(GPIOB, GPIO_PIN_8);
    BSP_LED_Init(GPIOB, GPIO_PIN_9);
    BSP_KEY2_Init(BUTTON_MODE_EXTI);
    BSP_USART1_Init(115200);
    printf("Exti Stop mode\r\n");
    while (1)
    {
        printf("RUNNING\r\n");
        delay_ms(200);
    }
}

串口工具查看是否实现RTC闹钟5s唤醒STOP模式,通过串口工具查看确实是已经实现RTC闹钟定时唤醒STOP模式。

image.png

使用特权

评论回复
沙发
夜幕叙事曲| | 2025-7-1 10:22 | 只看该作者
这个RTC的电力消耗算哪里的啊?

使用特权

评论回复
板凳
heyanmei|  楼主 | 2025-7-1 19:44 | 只看该作者
本帖最后由 heyanmei 于 2025-7-2 15:45 编辑
夜幕叙事曲 发表于 2025-7-1 10:22
这个RTC的电力消耗算哪里的啊?

RTC算备份域的,如果VDD断电,VBAT供电,备份域就是VBAT供电的,如果VDD没断电,备份域就是VDD供电

使用特权

评论回复
地板
jobszheng| | 2025-7-3 10:17 | 只看该作者
这个实验要做一做。低功耗必备的方案与策略。

使用特权

评论回复
5
夜幕叙事曲| | 2025-7-3 23:38 | 只看该作者
heyanmei 发表于 2025-7-1 19:44
RTC算备份域的,如果VDD断电,VBAT供电,备份域就是VBAT供电的,如果VDD没断电,备份域就是VDD供电 ...

也是啊!
即使我vbat没有电了,理论上,我连接着VDD,这块备份区我也能操作。

使用特权

评论回复
6
穷得响叮当侠| | 2025-7-4 14:43 | 只看该作者
这个帖子详细介绍了APM32F402如何通过RTC定时器实现从STOP模式唤醒,非常实用!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

13

帖子

0

粉丝