APM32F072单片机进入STOP模式,并通过RTC Wakeup Timer和USART1串口接收事件唤醒

串口初始化(注意USART1时钟源要选择HSI):

void usart_init(int baud_rate)
{
    GPIO_Config_T gpio;
    USART_Config_T usart;
    
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
    
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_9, GPIO_AF_PIN1);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_10, GPIO_AF_PIN1);
    
    gpio.mode = GPIO_MODE_AF;
    gpio.outtype = GPIO_OUT_TYPE_PP;
    gpio.pin = GPIO_PIN_9 | GPIO_PIN_10;
    gpio.pupd = GPIO_PUPD_PU;
    gpio.speed = GPIO_SPEED_2MHz;
    GPIO_Config(GPIOA, &gpio);
    
    RCM_ConfigUSARTCLK(RCM_USART1CLK_HSI);
    USART_ConfigStructInit(&usart);
    usart.baudRate = (uint32_t)baud_rate;
    USART_Config(USART1, &usart);
    USART_ConfigOverrunDetection(USART1, USART_OVER_DETECTION_DISABLE);
    USART_Enable(USART1);
}

使用power_init函数初始化RTC,然后调用power_enter_stop_mode(n)函数进入STOP模式,n秒后自动唤醒,或由USART1接收唤醒:

#include <apm32f0xx_eint.h>
#include <apm32f0xx_pmu.h>
#include <apm32f0xx_rcm.h>
#include <apm32f0xx_rtc.h>
#include <apm32f0xx_usart.h>
#include <stdio.h>
#include "bc3602.h"
#include "common.h"
#include "power.h"

static void power_rtc_init(void);
static void power_rtc_wakeup_init(void);
static void power_usart_wakeup_init(void);

void power_enter_stop_mode(uint16_t seconds)
{
    // enable the wakeup timer
    RTC_SetWakeUpValue(seconds - 1);
    RTC_EnableWakeUp();
    
    // enter STOP mode with two WFE instructions
    printf("Enter STOP mode\n");
    fflush(stdout);
    bc3602_suspend();
    PMU_EnterSTOPMode(PMU_REGULATOR_LowPower, PMU_STOPENTRY_WFE); // clear the event register
    PMU_EnterSTOPMode(PMU_REGULATOR_LowPower, PMU_STOPENTRY_WFE); // enter stop mode
    bc3602_resume();
    printf("Wakeup\n");
    
    // disable the wakeup timer
    RTC_DisableWakeUp();
    if (RTC_ReadIntFlag(RTC_INT_FLAG_WT) != RESET)
    {
        RTC_ClearIntFlag(RTC_INT_FLAG_WT);
        printf("RTC wakeup timer event\n");
    }
    
    // clear USART wakeup flag
    if (USART_ReadIntFlag(USART1, USART_INT_FLAG_WAKEUP) != RESET)
    {
        USART_ClearIntFlag(USART1, USART_INT_FLAG_WAKEUP);
        printf("USART event\n");
    }
}

void power_init(void)
{
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
    PMU_EnableBackupAccess();
    
    power_rtc_init();
    power_rtc_wakeup_init();
    power_usart_wakeup_init();
}

static void power_rtc_init(void)
{
    uint32_t freq, interval, synch;
    uint32_t last, now;
    RTC_Config_T rtc;
    
    if (RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET)
    {
        printf("LSI is OFF\n");
        RCM_EnableLSI();
        while (RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
        printf("LSI is ready\n");
    }
    else
    {
        printf("LSI is ON\n");
    }
    
    if (!RCM->BDCTRL_B.RTCCLKEN)
    {
        RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
        RCM_EnableRTCCLK();
    
        rtc.format = RTC_HourFormat_12;
        rtc.AsynchPrediv = 124;
        rtc.SynchPrediv = 319;
        RTC_Config(&rtc);
        printf("RTC is configured\n");
        
        // CAUTION: Once the wakeup timer is started, it does NOT stop until the MCU loses power supply
        RTC_ConfigWakeUpClock(RTC_WAKEUP_CLOCK_CK_SPRE_16B);
        RTC_SetWakeUpValue(0);
        RTC_EnableWakeUp();
        
        while (RTC_ReadStatusFlag(RTC_FLAG_WTF) == RESET);
        last = sys_now();
        RTC_ClearStatusFlag(RTC_FLAG_WTF);
        while (RTC_ReadStatusFlag(RTC_FLAG_WTF) == RESET);
        now = sys_now();
        RTC_ClearStatusFlag(RTC_FLAG_WTF);
        RTC_DisableWakeUp();
        
        interval = now - last;
        freq = 40000000 / interval;
        synch = (10 * freq) / (rtc.AsynchPrediv + 1) - 10; // 10*(freq/(asynch+1)-1)
        synch = (synch + 5) / 10; // round off the number
        printf("RTC calibration: interval=%u, freq=%u, synch=%u\n", interval, freq, synch);
        if (synch != rtc.SynchPrediv)
        {
            rtc.SynchPrediv = synch;
            RTC_Config(&rtc);
            printf("RTC is calibrated\n");
        }
    }
}

static void power_rtc_wakeup_init(void)
{
    EINT_Config_T eint;
    
    // configure EINT20 (RTC wakeup interrupt) as event mode
    eint.line = EINT_LINE20;
    eint.lineCmd = ENABLE;
    eint.mode = EINT_MODE_EVENT;
    eint.trigger = EINT_TRIGGER_RISING;
    EINT_Config(&eint);
    
    RTC_EnableInterrupt(RTC_INT_WT);
}

static void power_usart_wakeup_init(void)
{
    EINT_Config_T eint;
    
    // configure EINT25 (USART1 wakeup interrupt) as event mode
    eint.line = EINT_LINE25;
    eint.lineCmd = ENABLE;
    eint.mode = EINT_MODE_EVENT;
    eint.trigger = EINT_TRIGGER_RISING;
    EINT_Config(&eint);
    
    while (USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET);
    USART_Disable(USART1);
    USART_ConfigStopModeWakeUpSource(USART1, USART_WAKEUP_SOURCE_RXNE);
    USART_Enable(USART1);
    
    USART_EnableStopMode(USART1);
    USART_EnableInterrupt(USART1, USART_INT_WAKEUP);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用HAL库函数在STM32F1系列的MCU上实现进入停止模式并配置RTC唤醒和外部事件唤醒的代码示例: ``` // 使能RTC时钟 __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_BKP_CLK_ENABLE(); __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET); __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); __HAL_RCC_RTC_ENABLE(); // 配置RTC唤醒 HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x0800, RTC_WAKEUPCLOCK_RTCCLK_DIV16); HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn); HAL_PWR_ClearFlag(PWR_FLAG_WU); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 配置外部事件唤醒 HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); ``` 在使用HAL库函数实现进入停止模式时,需要先使用HAL_Init()函数初始化HAL库。 在配置RTC唤醒时,可以使用HAL_RTCEx_SetWakeUpTimer_IT()函数设置唤醒时间,并使用HAL_NVIC_EnableIRQ()函数使能RTC唤醒中断。在进入停止模式前,需要执行HAL_PWR_ClearFlag()函数清除唤醒标志。 在配置外部事件唤醒时,可以使用HAL_PWR_EnableWakeUpPin()函数使能唤醒引脚,并使用HAL_PWR_DisableWakeUpPin()函数禁用唤醒引脚。同样需要在进入停止模式前执行HAL_PWR_EnterSTOPMode()函数。 需要注意的是,在使用外部事件唤醒时,需要将唤醒引脚连接到一个外部事件,例如外部中断、定时器计数器溢出等。当外部事件发生时,唤醒引脚会产生一个高电平信号,从而唤醒MCU。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巨大八爪鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值