关于stm32L051进入stop模式后被rtc的alarm中断唤醒的执行顺序问题

[复制链接]
keer_zu 发表于 2025-8-19 23:56 | 显示全部楼层 |阅读模式

问题:

`stm32l051执行以下代码进入stop模式:
void Enter_Stop_Mode(void)
{
// 1. 配置RTC为唤醒源
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);

// 2. 挂起SysTick
HAL_SuspendTick();

// 3. 进入Stop模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

// 4. 唤醒后重新配置时钟
SystemClock_Config();
HAL_ResumeTick();
}
如果被rtc的alarm中断唤醒,请问是先执行RTC的中断函数RTC_IRQHandler,还是 紧接着HAL_PWR_EnterSTOPMode之后的代码:
// 4. 唤醒后重新配置时钟
SystemClock_Config();
HAL_ResumeTick();`

 楼主| keer_zu 发表于 2025-8-19 23:58 | 显示全部楼层

这个问题涉及到STM32低功耗模式的中断唤醒机制。

答案是:先执行RTC的中断服务函数(RTC_IRQHandler),然后再返回到 HAL_PWR_EnterSTOPMode 函数之后的代码(即 SystemClock_Config())继续执行。

下面是详细的执行流程和原理分析:

唤醒过程详细流程

  1. 进入Stop模式

    • 当代码执行 HAL_PWR_EnterSTOPMode() 中的 WFI (Wait For Interrupt) 指令后,内核停止执行,芯片进入低功耗的Stop模式。
  2. RTC Alarm事件发生

    • RTC计时到达设定的闹钟时间,触发了Alarm事件。
  3. 产生中断请求

    • RTC Alarm事件会置位相应的中断标志位,并向NVIC(嵌套向量中断控制器)发出一个中断请求。
  4. 芯片唤醒

    • 这个中断请求会将芯片从Stop模式中唤醒。内核退出睡眠状态,时钟恢复。
  5. 执行中断服务程序

    • 唤醒后,内核的第一要务是处理中断。NVIC会检查中断源,并跳转到对应的中断向量表,找到 RTC_IRQHandler 函数的地址并开始执行。
    • RTC_IRQHandler 内部,通常会调用 HAL_RTC_AlarmIRQHandler 这个函数来处理Alarm中断,它会清除中断标志位并调用您事先设置好的回调函数(例如 HAL_RTC_AlarmAEventCallback)。
  6. 退出中断服务程序

    • 中断服务程序执行完毕后,使用 BX LR 指令返回。这个返回地址,正是当初执行 WFI 指令后,程序计数器(PC)保存的下一条指令的地址。
  7. 继续执行主程序

    • 从中断返回后,程序流程就回到了 HAL_PWR_EnterSTOPMode 函数内部(紧跟在 WFI 指令之后)。该函数会执行一些必要的清理工作后也返回。
    • 最终,代码继续执行 Enter_Stop_Mode 函数中 HAL_PWR_EnterSTOPMode 之后的代码,即重新配置系统时钟 SystemClock_Config() 和恢复SysTick HAL_ResumeTick()

为什么需要这样设计?

这种“先中断,后主流程”的设计是中断系统的标准行为,非常合理:

  • 实时性:中断的核心目的是为了立即响应一个紧急事件。确保中断服务程序最先执行,可以最快地对事件做出处理(例如,记录唤醒时间、设置一个标志位、执行一个关键操作)。
  • 安全性HAL_PWR_EnterSTOPMode 之后的代码(尤其是 SystemClock_Config())通常涉及对时钟树的重要配置。确保在配置时钟之前,所有可能依赖旧时钟的中断都已经处理完毕,可以避免潜在的错误。

代码编写建议

在您的代码中,通常会在RTC Alarm中断服务程序(或其回调函数)中做一些“轻量级”的操作,例如设置一个全局的标志变量 rtc_wakeup_flag = 1;

而在主循环或 Enter_Stop_Mode 函数之后,你再检查这个标志位,来决定后续要执行哪些具体的任务(例如读取传感器数据并发送)。

// 定义一个全局变量
volatile uint8_t rtc_wakeup_flag = 0;

// RTC Alarm回调函数(在中断上下文被调用)
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
  rtc_wakeup_flag = 1; // 仅仅设置标志位,不执行耗时操作
}

void Enter_Stop_Mode(void)
{
  // ... 进入Stop模式前的配置 ...
  HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
  // 从这里开始,是唤醒后执行的地方
  SystemClock_Config();
  HAL_ResumeTick();

  // 检查唤醒标志,执行后续应用逻辑
  if(rtc_wakeup_flag == 1) {
    rtc_wakeup_flag = 0;
    // 执行你的主要任务,例如:
    Read_Sensor();
    Send_Data();
  }

  // 任务执行完后,可以再次进入Stop模式
  // Enter_Stop_Mode(); 
  // 注意:在实际应用中,这可能会是一个循环,或者由主循环控制。
}

总结

顺序 执行内容 上下文
1 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); 主程序
2 (芯片进入Stop模式) -
3 RTC Alarm事件发生,芯片唤醒 硬件事件
4 RTC_IRQHandler / HAL_RTC_AlarmIRQHandler / HAL_RTC_AlarmAEventCallback 中断服务程序
5 SystemClock_Config(); 主程序(Enter_Stop_Mode函数)
6 HAL_ResumeTick(); 主程序(Enter_Stop_Mode函数)
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1477

主题

12909

帖子

55

粉丝
快速回复 在线客服 返回列表 返回顶部