2. 进入睡眠模式

任务定义

本案例目标:在STM32L0系列MCU上实现通过RTC闹钟事件周期性唤醒的STOP模式低功耗运行。具体要求:MCU进入STOP模式后电流降至µA级,RTC闹钟每10秒触发一次唤醒,唤醒后翻转一次LED状态并重新进入睡眠,形成可观测的周期性唤醒循环。

硬件连接与测量拓扑

STM32L052 STOP Mode PA0 PB5 NRST 3.3V LDO VDD GND LED 330Ω µA 表 串联 VDD 32.768kHz PB5 → LED PA0 → 唤醒引脚 (可选外部唤醒) ← 电流测量点

实现代码

以下代码基于STM32L0系列HAL库,使用RTC唤醒定时器(WakeUp Timer)实现周期唤醒,无需外部中断引脚即可完成定时唤醒功能。


// main.c — STM32L052 STOP模式RTC周期唤醒
#include "stm32l0xx_hal.h"

/* 私有变量 */
static RTC_HandleTypeDef hrtc;

/* LED控制引脚 — PB5 */
#define LED_PIN       GPIO_PIN_5
#define LED_PORT      GPIOB

/* 函数声明 */
static void SystemClock_Config(void);
static void RTC_WakeUp_Init(void);
static void GPIO_LED_Init(void);

int main(void)
{
    /* 复位所有外设,初始化Flash接口和SysTick */
    HAL_Init();
    SystemClock_Config();
    GPIO_LED_Init();
    RTC_WakeUp_Init();

    /* 初始LED状态:灭 */
    HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET);

    while (1)
    {
        /* 进入STOP模式,RTC闹钟唤醒 */
        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

        /* 系统时钟从MSI重新启动 */
        SystemClock_Config();

        /* 唤醒后翻转LED */
        HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
    }
}

/**
 * RTC初始化:配置为唤醒定时器模式,周期10秒
 * 使用LSI时钟(37kHz)作为RTC时钟源
 */
static void RTC_WakeUp_Init(void)
{
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_RCC_RTC_ENABLE();

    hrtc.Instance = RTC;
    hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
    hrtc.Init.AsynchPrediv = 0x7F;    /* 128分频 */
    hrtc.Init.SynchPrediv  = 0x00;    /* 1分频 */
    hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
    hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;

    if (HAL_RTC_Init(&hrtc) != HAL_OK)
    {
        Error_Handler();
    }

    /* 使能唤醒定时器,周期 = (0xFFFF - 0x0F) / 128 ≈ 10秒 */
    /* 实际计算:LSI≈37kHz,128分频后≈289Hz */
    /* 10秒 ≈ 2890个计数,取0x0B4A = 2890 */
    HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x0B4A, RTC_WAKEUPCLOCK_RTCCLK_DIV128);
}

/**
 * GPIO初始化:PB5配置为推挽输出,驱动LED
 */
static void GPIO_LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin   = LED_PIN;
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull  = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
}

/**
 * 系统时钟配置:MSI 2.097MHz作为系统时钟
 * 进入STOP模式前调用,唤醒后重新配置
 */
static void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /* MSI 2.097MHz */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.MSIState       = RCC_MSI_ON;
    RCC_OscInitStruct.MSIClockRange  = RCC_MSIRANGE_5;  /* 2.097MHz */
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /* AHB/APB时钟配置 */
    RCC_ClkInitStruct.ClockType      = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                       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;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * RTC唤醒中断回调 — 空实现,仅用于清除中断标志
 */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
    /* 中断标志由HAL库自动清除 */
}

/**
 * 错误处理
 */
void Error_Handler(void)
{
    __disable_irq();
    while (1)
    {
    }
}

关键配置说明

参数值说明
RTC时钟源LSI (~37kHz)STOP模式下保持运行,无需外部晶振
异步预分频128RTC时钟 = 37kHz / 128 ≈ 289Hz
唤醒计数值0x0B4A (2890)唤醒周期 ≈ 2890 / 289 ≈ 10秒
系统时钟MSI 2.097MHz唤醒后快速启动,无需PLL稳定时间
低功耗模式STOP内核停止,SRAM和寄存器内容保持

编译与烧录


# 使用STM32CubeIDE或Makefile工程编译
# 关键编译选项(以arm-none-eabi-gcc为例)
arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb \
  -DSTM32L052xx -IInc \
  -c main.c -o main.o

# 链接生成固件
arm-none-eabi-ld -T stm32l052.ld main.o ... -o firmware.elf

# 通过ST-Link烧录
st-flash write firmware.bin 0x08000000

验证方法与判定标准

电流测量:将µA级电流表串联在MCU的VDD供电回路中(参考上方SVG拓扑),观察STOP模式下的稳态电流。判定标准:电流读数应小于5µA(典型值1-3µA)。若电流偏高,检查是否有GPIO悬空、未使用的外设未关闭或调试接口仍处于激活状态。

唤醒周期验证:用示波器探头连接PB5引脚,观察LED驱动波形。判定标准:应看到周期约10秒的方波翻转,高电平持续到下一次唤醒翻转。若周期偏差超过±2秒,需校准LSI频率或调整唤醒计数值。

功能完整性:程序运行后LED以10秒间隔持续翻转,说明MCU成功进入STOP模式并被RTC唤醒。若LED不翻转,检查RTC中断是否使能(NVIC)、唤醒定时器是否启动。

注意:以上验证方法描述的是预期操作流程与判定条件,实际测量数据需在目标硬件上执行后获得。