STM32L051同时处理Alarm A和Alarm B中断

同时处理Alarm A和Alarm B中断

当同时启用Alarm A和Alarm B时,需要在中断处理程序中准确判断是哪个闹钟触发了中断。以下是完整的解决方案:

中断判断与处理流程

1. 在RTC中断服务程序中判断中断源

c 复制代码
// stm32l0xx_it.c
void RTC_IRQHandler(void)
{
    /* USER CODE BEGIN RTC_IRQn 0 */
    
    // 检查Alarm A中断标志
    if (__HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_ISR_ALRAF) != RESET)
    {
        // 清除Alarm A中断标志
        __HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRAF);
        
        // 处理Alarm A中断
        AlarmA_Handler();
        
        printf("Alarm A Triggered\n");
    }
    
    // 检查Alarm B中断标志
    if (__HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_ISR_ALRBF) != RESET)
    {
        // 清除Alarm B中断标志
        __HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRBF);
        
        // 处理Alarm B中断
        AlarmB_Handler();
        
        printf("Alarm B Triggered\n");
    }
    
    // 检查Wakeup定时器中断标志
    if (__HAL_RTC_WAKEUPTIMER_GET_FLAG(&hrtc, RTC_ISR_WUTF) != RESET)
    {
        // 清除Wakeup中断标志
        __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
        
        // 处理Wakeup中断
        WakeUp_Handler();
        
        printf("WakeUp Timer Triggered\n");
    }
    
    /* USER CODE END RTC_IRQn 0 */
    
    // 调用HAL库的中断处理函数
    HAL_RTC_AlarmIRQHandler(&hrtc);
    HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc);
    
    /* USER CODE BEGIN RTC_IRQn 1 */
    /* USER CODE END RTC_IRQn 1 */
}

2. 实现各中断的处理函数

c 复制代码
// alarm_handlers.c
#include "alarm_handlers.h"

// Alarm A处理函数
void AlarmA_Handler(void)
{
    // 执行Alarm A特定的任务
    HAL_GPIO_TogglePin(LED_A_GPIO_Port, LED_A_Pin);
    
    // 可以在此重新设置Alarm A
    // Reset_AlarmA();
}

// Alarm B处理函数
void AlarmB_Handler(void)
{
    // 执行Alarm B特定的任务
    HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin);
    
    // 可以在此重新设置Alarm B
    // Reset_AlarmB();
}

// Wakeup处理函数
void WakeUp_Handler(void)
{
    // 执行唤醒后的任务
    printf("System Woke Up from Stop Mode\n");
    
    // 禁用Wakeup定时器(除非需要再次使用)
    HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
}

完整的中断处理流程

ALRAF置位 ALRBF置位 WUTF置位 RTC中断触发 检查中断标志 处理Alarm A 处理Alarm B 处理Wakeup 清除ALRAF标志 清除ALRBF标志 清除WUTF标志 执行Alarm A任务 执行Alarm B任务 执行Wakeup任务 退出中断

关键配置说明

1. 中断标志位

  • Alarm A : RTC_ISR_ALRAF (寄存器ISR的位0)
  • Alarm B : RTC_ISR_ALRBF (寄存器ISR的位1)
  • Wakeup定时器 : RTC_ISR_WUTF (寄存器ISR的位2)

2. 清除中断标志

  • 使用__HAL_RTC_ALARM_CLEAR_FLAG()宏清除Alarm标志
  • 清除标志后,中断挂起位也会自动清除

3. 中断优先级处理

当多个中断同时发生时,处理顺序取决于检查顺序:

  1. 先检查Alarm A
  2. 然后检查Alarm B
  3. 最后检查Wakeup定时器

如果需要改变优先级,可以调整检查顺序。

设置双闹钟的示例代码

1. 配置Alarm A和Alarm B

c 复制代码
// rtc.c
void MX_RTC_Init(void)
{
    // ... 其他初始化代码
    
    // 配置Alarm A
    RTC_AlarmTypeDef sAlarmA = {0};
    sAlarmA.AlarmTime.Hours = 0x0;
    sAlarmA.AlarmTime.Minutes = 0x0;
    sAlarmA.AlarmTime.Seconds = 0x20; // 32秒触发
    sAlarmA.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS | RTC_ALARMMASK_MINUTES;
    sAlarmA.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
    sAlarmA.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
    sAlarmA.AlarmDateWeekDay = 0x1;
    sAlarmA.Alarm = RTC_ALARM_A;
    if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarmA, RTC_FORMAT_BCD) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置Alarm B
    RTC_AlarmTypeDef sAlarmB = {0};
    sAlarmB.AlarmTime.Hours = 0x0;
    sAlarmB.AlarmTime.Minutes = 0x1;  // 1分钟触发
    sAlarmB.AlarmTime.Seconds = 0x0;
    sAlarmB.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS | RTC_ALARMMASK_SECONDS;
    sAlarmB.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
    sAlarmB.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
    sAlarmB.AlarmDateWeekDay = 0x1;
    sAlarmB.Alarm = RTC_ALARM_B;
    if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarmB, RTC_FORMAT_BCD) != HAL_OK)
    {
        Error_Handler();
    }
}

2. 中断处理优化建议

  1. 避免在中断中执行耗时操作

    c 复制代码
    void AlarmA_Handler(void)
    {
        // 仅设置标志,在主循环中处理
        alarmA_triggered = true;
    }
  2. 处理同时触发的情况

    c 复制代码
    if (__HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_ISR_ALRAF) && 
        __HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_ISR_ALRBF))
    {
        // 处理双闹钟同时触发的情况
        Handle_Dual_Alarm();
    }
  3. 添加错误处理

    c 复制代码
    if (__HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_ISR_ALRAWF))
    {
        // Alarm A写入正在进行中
        printf("Alarm A register is being written\n");
    }

调试技巧

  1. 使用GPIO调试

    c 复制代码
    void AlarmA_Handler(void)
    {
        HAL_GPIO_WritePin(DEBUG_A_GPIO_Port, DEBUG_A_Pin, GPIO_PIN_SET);
        // ... 处理代码
        HAL_GPIO_WritePin(DEBUG_A_GPIO_Port, DEBUG_A_Pin, GPIO_PIN_RESET);
    }
  2. 记录中断时间

    c 复制代码
    void AlarmA_Handler(void)
    {
        HAL_RTC_GetTime(&hrtc, &lastAlarmATime, RTC_FORMAT_BIN);
        // ... 其他处理
    }
  3. 检查中断频率

    c 复制代码
    static uint32_t alarmA_count = 0;
    void AlarmA_Handler(void)
    {
        alarmA_count++;
        if (alarmA_count % 10 == 0) {
            printf("Alarm A triggered %lu times\n", alarmA_count);
        }
    }

通过以上方案,您可以准确区分和处理Alarm A、Alarm B以及Wakeup定时器的中断,实现复杂的定时任务调度。

相关推荐
Zevalin爱灰灰3 小时前
能源与电源管理电路——防倒灌电路
单片机·嵌入式硬件·电源管理
jianqiang.xue6 小时前
ESP-IDF保姆级入门02|Ubuntu24.04搭建EIM-GUI开发环境,打通Windows_Linux双平台统一开发
stm32·单片机·物联网
无垠的广袤6 小时前
【工业树莓派 CM0 Dev Board】扩展板设计
linux·python·嵌入式硬件·pcb设计·模块化·传感器
嵌入式-老费7 小时前
esp32开发与应用(添加数据分区)
单片机·嵌入式硬件
嵌入式-老费8 小时前
esp32开发与应用(OTA升级)
嵌入式硬件
CYLAM202510 小时前
STC32G 单片机0.96“OLED 西历农历可调万年历 (1901-2100)
单片机·嵌入式硬件·stc32g·万年历·西历农历·0.96”oled 12864·4x4 矩阵键盘
Discipline~Hai11 小时前
ARM03-蜂鸣器和中断
c语言·arm开发·单片机·嵌入式硬件·嵌入式
KaifuZeng12 小时前
电源面试问题汇总一
单片机·嵌入式硬件·面试·电路
驱动探索者13 小时前
RISC-V PLIC 深度解析:从 Spec 到 Zephyr 驱动实现
单片机·嵌入式硬件·中断控制器
LCG元14 小时前
STM32 FreeRTOS 实战:任务调度 + 互斥锁 + 消息队列 + 串口命令解析器
stm32·单片机·嵌入式硬件