3. RTC定时唤醒周期性任务

RTC定时唤醒周期性任务 学习卡片

任务定义

本案例要求MCU在低功耗模式下,依靠RTC周期性中断实现定时唤醒,每次唤醒后执行一次传感器数据采集(以读取内部温度传感器代替外部传感器),随后重新进入低功耗,形成完整的“休眠—唤醒—采集—再休眠”循环。通过LED翻转指示唤醒事件发生,便于观测验证。

硬件连接与原理

  • MCU:STM32L431(Cortex-M4,支持STOP2低功耗模式)
  • RTC:LSE 32.768kHz晶振,配置为周期唤醒中断(WakeUp Timer)
  • 内部温度传感器:ADC通道17,无需外部接线
  • LED:PB2,唤醒后翻转一次,用于指示唤醒事件
  • 按键:PA0(外部中断EXTI0),用于手动触发一次唤醒,便于快速验证
唤醒时序:MCU进入STOP2模式 → RTC计数溢出产生唤醒事件 → 系统时钟恢复 → 执行ADC采集 → 翻转LED → 再次进入STOP2
RTC定时唤醒周期性任务时序 运行态(采集) STOP2低功耗 运行态(采集) STOP2低功耗 RTC唤醒中断 RTC唤醒中断 唤醒周期 T = 5秒(可配置) 唤醒后执行流程 1. 配置ADC通道17 2. 启动转换并读取温度值 3. 翻转PB2 LED 4. 清除RTC唤醒标志 进入STOP2前配置 1. 设置RTC唤醒周期 2. 使能RTC唤醒中断 3. 调用 HAL_PWR_EnterSTOPMode 4. 唤醒后重配系统时钟 PA0按键 手动唤醒

代码实现

以下代码基于STM32CubeMX生成的HAL工程,核心逻辑位于main.c中。RTC配置为LSE时钟源,唤醒周期设为5秒。

/* main.c 核心代码 */
#include "main.h"
#include "adc.h"
#include "rtc.h"
#include "gpio.h"

/* 私有变量 */
static uint32_t wakeup_count = 0;   /* 唤醒次数计数 */
static uint16_t temp_raw = 0;       /* ADC原始值 */

/* 函数声明 */
void SystemClock_Config(void);
void Enter_Stop2_Mode(void);
void Read_Temperature(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  
  /* 初始化外设 */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_RTC_Init();
  
  /* 使能RTC唤醒中断 */
  HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 5000, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
  /* 5000 × (1/32768×16) ≈ 2.44秒,实际唤醒周期约2.44秒 */
  
  /* 初始LED状态 */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
  
  while (1)
  {
    /* 进入STOP2低功耗模式 */
    Enter_Stop2_Mode();
    
    /* 唤醒后执行:读取温度并翻转LED */
    Read_Temperature();
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2);
    wakeup_count++;
  }
}

/**
  * @brief 进入STOP2模式
  */
void Enter_Stop2_Mode(void)
{
  /* 确保RTC唤醒中断已使能 */
  HAL_SuspendTick();  /* 暂停SysTick,避免唤醒后时钟混乱 */
  
  /* 进入STOP2模式 */
  HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
  
  /* 唤醒后重新配置系统时钟 */
  SystemClock_Config();
  HAL_ResumeTick();
}

/**
  * @brief 读取内部温度传感器
  */
void Read_Temperature(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
  
  /* 配置ADC通道17(内部温度传感器) */
  sConfig.Channel = ADC_CHANNEL_17;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLINGTIME_39CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  /* 启动ADC转换 */
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1, 100);
  temp_raw = HAL_ADC_GetValue(&hadc1);
  HAL_ADC_Stop(&hadc1);
  
  /* 温度计算:V25=0.76V,Avg_Slope=2.5mV/°C */
  /* 实际温度 = (VADC - V25)/Avg_Slope + 25 */
}

/**
  * @brief RTC唤醒中断回调(在stm32l4xx_it.c中调用)
  */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
  /* 清除唤醒标志由HAL库自动处理 */
  /* 此回调在中断上下文中执行,仅做标志操作 */
  /* 实际采集工作放在主循环中执行 */
}

/**
  * @brief EXTI0中断回调(PA0按键)
  */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == GPIO_PIN_0)
  {
    /* 按键唤醒后,主循环会执行一次采集 */
    /* 无需额外处理 */
  }
}

关键配置说明

配置项值说明
RTC时钟源LSE 32.768kHz低功耗模式下保持运行
唤醒时钟分频RTC_WAKEUPCLOCK_RTCCLK_DIV16实际计数时钟 = 32768/16 = 2048Hz
唤醒计数值5000唤醒周期 ≈ 5000/2048 ≈ 2.44秒
低功耗模式STOP2保留RTC和备份域供电
ADC通道17(内部温度)无需外部传感器

编译与烧录

  1. 使用STM32CubeMX生成工程,勾选RTC、ADC1、GPIO外设
  2. 在stm32l4xx_it.c中确保调用HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc)
  3. 编译工程:make 或使用IDE(Keil/IAR)
  4. 烧录:STM32_Programmer_CLI -c port=SWD -w build/main.hex

验证方法

判定标准:观察PB2连接的LED以约2.44秒为周期闪烁,每次闪烁代表一次RTC唤醒并完成ADC采集。可通过以下方式进一步验证:

  • 在Read_Temperature()中设置断点,每次唤醒后应触发一次
  • 查看temp_raw变量值,应随环境温度变化(范围约1000~1800)
  • 按下PA0按键可立即触发一次唤醒,LED应快速翻转一次
  • 测量整机功耗:STOP2模式下电流应低于10μA(典型值)

预期输出:LED以约2.44秒间隔持续闪烁;wakeup_count变量每唤醒一次增加1;temp_raw值在室温下约为1300±200(具体值取决于芯片个体差异)。