3. 进入深度睡眠模式

进入深度睡眠模式 学习卡片

任务定义

本案例要求在STM32L4系列MCU上实现深度睡眠模式(Stop 2模式)的进入与唤醒。目标是通过RTC闹钟事件在10秒后唤醒MCU,验证系统能够从深度睡眠状态正确恢复并继续执行主程序。需要完成的工作包括:配置RTC闹钟中断、进入Stop 2模式、在唤醒后确认系统时钟恢复且程序流程正确衔接。

硬件连接与前置条件

使用NUCLEO-L476RG开发板,板载LED2(PB2引脚)用于指示运行状态。系统时钟配置为MSI 4MHz,RTC使用LSE外部32.768kHz晶振。需要确保开发板上LSE晶振的焊桥SB存在(默认已连接)。

代码实现


#include "stm32l4xx_hal.h"

/* 唤醒标志 */
volatile uint8_t wakeup_flag = 0;

/* RTC闹钟回调 */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    wakeup_flag = 1;
}

/* RTC初始化 */
static void MX_RTC_Init(void)
{
    RTC_HandleTypeDef hrtc = {0};
    RTC_AlarmTypeDef sAlarm = {0};

    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_RCC_RTC_ENABLE();
    __HAL_RCC_LSE_CONFIG(RCC_LSE_ON);

    while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {}

    hrtc.Instance = RTC;
    hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
    hrtc.Init.AsynchPrediv = 127;
    hrtc.Init.SynchPrediv = 255;
    hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
    hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
    HAL_RTC_Init(&hrtc);

    /* 设置闹钟A:10秒后触发 */
    sAlarm.AlarmTime.Hours = 0;
    sAlarm.AlarmTime.Minutes = 0;
    sAlarm.AlarmTime.Seconds = 10;
    sAlarm.AlarmTime.SubSeconds = 0;
    sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
    sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
    sAlarm.Alarm = RTC_ALARM_A;
    HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
}

/* GPIO初始化 */
static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    /* LED2 - PB2 */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/* 进入Stop 2模式 */
static void Enter_Stop2_Mode(void)
{
    HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
    
    /* 唤醒后重新配置系统时钟 */
    SystemClock_Config();
}

/* 系统时钟配置(MSI 4MHz) */
static void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_4;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
                                  RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_RTC_Init();

    /* 主循环 */
    while (1)
    {
        /* LED亮表示运行态 */
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_Delay(100);

        /* LED灭后进入深度睡眠 */
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
        HAL_Delay(100);

        /* 进入Stop 2模式 */
        Enter_Stop2_Mode();

        /* 唤醒后执行 */
        if (wakeup_flag)
        {
            wakeup_flag = 0;
            /* LED闪烁3次表示唤醒成功 */
            for (int i = 0; i < 3; i++)
            {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
                HAL_Delay(200);
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
                HAL_Delay(200);
            }
        }
    }
}

代码说明

上述代码实现了完整的深度睡眠进入与唤醒流程。主程序先点亮LED 100ms表示运行状态,然后熄灭LED并调用HAL_PWREx_EnterSTOP2Mode()进入Stop 2模式。RTC闹钟在10秒后触发中断,将wakeup_flag置1并唤醒MCU。唤醒后系统时钟需要重新配置(因为Stop 2模式会丢失时钟配置),随后检测到唤醒标志后LED闪烁3次作为成功指示。

验证方法

将代码编译后烧录至NUCLEO-L476RG开发板,观察以下现象:

  1. 上电后LED2先亮100ms后熄灭;
  2. LED熄灭后约10秒(RTC闹钟周期),LED2开始闪烁3次(每次亮200ms、灭200ms);
  3. 闪烁结束后,程序回到主循环开头,LED再次亮100ms后熄灭,进入下一轮深度睡眠周期。

判定标准:若LED按照上述时序周期性动作,说明MCU成功进入Stop 2模式并在RTC闹钟触发后正确唤醒,系统时钟恢复且程序流程无异常。若LED无反应或闪烁时序不符,则检查RTC配置、LSE晶振是否起振以及中断回调是否正确注册。

功耗观测点

如需测量深度睡眠电流,可在LED熄灭后的10秒窗口内,使用万用表串联在开发板的IDD测量跳线处(J6),预期电流应降至微安级(典型值约1.1μA @ 3.3V,Stop 2模式)。注意测量时需断开调试器连接,否则调试接口会额外消耗电流。

Stop 2 模式进入与唤醒时序 t=0 t=10s 运行态 LED亮100ms 延时 Stop 2 深度睡眠模式 电流 ~1.1μA | 等待RTC闹钟 RTC闹钟触发 唤醒恢复 时钟重配+LED闪3次 状态说明: 正常运行(LED亮) 深度睡眠(LED灭,CPU停止) 唤醒恢复(时钟重配) RTC闹钟中断流程: RTC闹钟到达 唤醒MCU 执行中断回调 wakeup_flag = 1 关键注意点: • Stop 2模式会丢失系统时钟配置,唤醒后必须调用 SystemClock_Config() 重新配置 • RTC使用LSE时钟,在Stop 2模式下继续运行,保证闹钟功能 • 中断回调中仅置标志位,实际处理放在主循环中执行 • 测量功耗时需断开调试器,否则测量值偏大 进入睡眠 10秒后唤醒