打印
[APM32F1]

分别通过GPIO的中断、事件唤醒APM32F103xE的stop模式

[复制链接]
686|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

1 概述1.1 MCU低功耗模式
MCU处于死等状态时,可让MCU进入低功耗模式,或者降低系统工作时钟;当需要MCU执行动作时,可产生唤醒信号唤醒MCU,或者恢复至高速时钟。这样可以降低系统在整个运行期间的功耗,且不影响系统的运行。
APM32F103xEsleepstopstandby、备份域供电的低功耗工作模式。
通常是通过停止MCU的内部资源来降低功耗,例如关闭内核、关闭时钟源、调整电源域的工作模式、SRAM是否供电、关闭各种外设的时钟。不同的低功耗模式关闭的资源也不一样,具体内容可参考用户手册。
而且唤醒后,因为关闭的资源不同,恢复到进入低功耗模式的工作状态的动作也是不一样的,唤醒的时间也不一样。
1.2 唤醒方式
可通过MCU的内部资源唤醒MCU,例如GPIO、串口、SPI等外设。每种外设唤醒的方式由分为中断唤醒、事件唤醒,但并不是所有的外设都支持事件唤醒,手册中有专门描述支持的唤醒事件。使用事件唤醒,不需要配置对应的中断;使用中断方式唤醒后,会立刻进入对应的中断(前提是使能中断,且没有触发其它高优先级的中断)。
例如,GPIO即可支持事件唤醒,由支持中断唤醒,但是呢,各种低功耗模式下让不让你唤醒又是另一回事了,例如standby模式下,只支持WKUP引脚的上升沿、RTC闹钟事件、NRST引脚的外部复位、IWDT复位,GPIO产生的中断、事件就无法唤醒standby模式。
以下是记录了调试分别通过GPIO的中断、事件唤醒APM32F103xEstop模式的代码、现象。
2 硬件电路
选择的开发板是APM32F103ZEmini板。按键B2连接MCUPA0引脚,通过按键产生上升沿或者下降沿触发MCU中断或者产生事件唤醒MCU另外能唤醒standby模式的GPIO只有PA0,为了减少后续代码的开发,选择PA0作为唤醒GPIO
                              

3 代码
#include "main.h"
#include "apm32f10x_pmu.h"
#include "stdio.h"

void USART1_Init(void)
{
    GPIO_Config_T GPIO_ConfigStruct;
    USART_Config_T USART_ConfigStruct;
       
    RCM_EnableAPB2PeriphClock((RCM_APB2_PERIPH_T)(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_USART1));
  
    GPIO_ConfigStruct.mode = GPIO_MODE_AF_PP;
    GPIO_ConfigStruct.pin = GPIO_PIN_9;
    GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA, &GPIO_ConfigStruct);

    USART_ConfigStruct.baudRate = 115200;
    USART_ConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
    USART_ConfigStruct.mode = USART_MODE_TX;
    USART_ConfigStruct.parity = USART_PARITY_NONE;
    USART_ConfigStruct.stopBits = USART_STOP_BIT_1;
    USART_ConfigStruct.wordLength = USART_WORD_LEN_8B;
    USART_Config(USART1, &USART_ConfigStruct);

    USART_Enable(USART1);       
        while(USART_ReadStatusFlag(USART1, USART_FLAG_TXBE) == RESET);               
}

void T_PWR_SleepPA0EventWakeUp(void)
{
        GPIO_Config_T PA0_GPIO_Config;
        EINT_Config_T PA0_EVENT_Config;
       
        RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
               
        PA0_GPIO_Config.mode = GPIO_MODE_IN_PU;
        PA0_GPIO_Config.pin = GPIO_PIN_0;
        GPIO_Config(GPIOA, &PA0_GPIO_Config);
       
        PA0_EVENT_Config.line = EINT_LINE_0;
        PA0_EVENT_Config.mode = EINT_MODE_EVENT;
        PA0_EVENT_Config.trigger = EINT_TRIGGER_RISING;
        PA0_EVENT_Config.lineCmd = ENABLE;
        EINT_Config(&PA0_EVENT_Config);
         
        GPIO_ConfigEINTLine(GPIO_PORT_SOURCE_A, GPIO_PIN_SOURCE_0);       

        printf("1进入stop模式\n\r");
        PMU_EnterSTOPMode(PMU_REGULATOR_ON,PMU_STOP_ENTRY_WFE);
        SystemInit();

        USART1_Init();
        printf("2通过事件唤醒,退出stop模式\n\r\n\r");
}



void T_PWR_SleepPA0IntWakeUp(void)
{
        GPIO_Config_T PA0_GPIO_Config;
        EINT_Config_T PA0_Int_Config;
       
        RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
               
        PA0_GPIO_Config.mode = GPIO_MODE_IN_PU;
        PA0_GPIO_Config.pin = GPIO_PIN_0;
        GPIO_Config(GPIOA, &PA0_GPIO_Config);
       
        NVIC_EnableIRQRequest(EINT0_IRQn,0x01,0x01);
       
        PA0_Int_Config.line = EINT_LINE_0;
        PA0_Int_Config.mode = EINT_MODE_INTERRUPT;
        PA0_Int_Config.trigger = EINT_TRIGGER_RISING;
        PA0_Int_Config.lineCmd = ENABLE;
        EINT_Config(&PA0_Int_Config);
         
        GPIO_ConfigEINTLine(GPIO_PORT_SOURCE_A, GPIO_PIN_SOURCE_0);       

        printf("1进入stop模式\n\r");
        PMU_EnterSTOPMode(PMU_REGULATOR_ON,PMU_STOP_ENTRY_WFE);
        SystemInit();

        USART1_Init();
        printf("3通过中断唤醒,退出stop模式\n\r\n\r");
       
}

void EINT0_IRQHandler(void)
{
        if(EINT_ReadStatusFlag(EINT_LINE_0) != RESET)
        {
                EINT_ClearIntFlag(EINT_LINE_0);
                USART1_Init();
                printf("2通过中断唤醒,退出stop模式,进入中断处理函数EINT0_IRQHandler\n\r");       
        }
}

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
        USART_TxData(USART1, (char) ch);
        while(USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET);
        return (ch);
}

//重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
        while (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == RESET);
        return (int)USART_RxData(USART1);
}



int main(void)
{

        USART1_Init();
        T_PWR_SleepPA0EventWakeUp();
//        T_PWR_SleepPA0IntWakeUp();
    while(1)
    {
    }
}

4 现象4.1 通过事件唤醒stop模式,串口记录数据如下:

4.2 通过中断唤醒stop模式,串口记录数据如下:
通过中断唤醒,会优先进入中断处理函数。
5 Keil工程附件
stop_GPIO_interrupt_wakeup.zip (514.39 KB)


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:极海半导体
简介:珠海极海半导体有限公司是一家致力于开发工业级/车规级微控制器、模拟与混合信号IC及系统级芯片的集成电路设计型企业。极海团队拥有20年集成电路设计经验和嵌入式系统开发能力,可为客户提供核心可靠的芯片产品及方案,实现准确感应、安全传输和实时控制,助力客户在智慧家居、高端消费电子、工业控制、汽车电子、智慧能源以及通信设施等领域的拓展创新。

29

主题

68

帖子

0

粉丝