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 
#include 
#include 
#include 
#include 
#include 
#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);
}

你可能感兴趣的:(STM32,单片机,嵌入式硬件,RTC,STOP,USART)