一、WFI和WFE
WFI: wait for interrupt,是"等待中断"的意思;
WFE: wait for event,是"等待事件"的意思;
1)执行HAL_PWR_DisableSleepOnExit(),则令SLEEPONEXIT位置0;
当SLEEPDEEP=0,SLEEPONEXIT=0,如果执行WFI,则立即进入"sleep模式",中断唤醒后,程序会继续执行main()中的其它语句;
退出睡眠方式是:中断;
当SLEEPDEEP=0,SLEEPONEXIT=0,如果执行WFE,则立即进入"sleep模式",唤醒后,程序会继续执行main()中的其它语句;
退出睡眠方式是:唤醒事件,包括中断;
2)执行HAL_PWR_EnableSleepOnExit(),则令SLEEPONEXIT位置1;
若执行WFI或WFE,则立即进入"sleep模式";中断唤醒后,程序只执行"相应的中断服务程序",退出中断后,会再次进入"sleep模式",
因此,不再执行执行main()中的其它语句;
唤醒退出方式是:中断;
3)执行HAL_PWR_EnableSEVOnPend(),则令SEVONPEND位置1;允许事件唤醒内核(包括中断唤醒),
在执行WFE指令前,需要先设置SEVONPEND=1,才可以使用事件唤醒,否则,只能使用中断唤醒;
但通过WFI进入的"sleep模式",即使设置SEVONPEND=1,事件也无法唤醒CPU核,不清楚原因?
翻译的文档,写得实在糟糕,一些功能性表格,就不截图了,免得会产生误解!!!
4)"stop模式"可以执行事件唤醒和中断唤醒。
注意:在sleep模式中,所有的"IO引脚"和"run模式"保持相同的电平状态;
在进入睡眠前,需要配置好"相应的唤醒源",关闭不用的模块,如SysTick,以便CPU进入Sleep模式;
二、测试程序
#include "SleepMode.h"/*
"sleep模式"
WFI: wait for interrupt,是"等待中断"的意思;
WFE: wait for event,是"等待事件"的意思;1)执行HAL_PWR_DisableSleepOnExit(),则令SLEEPONEXIT位置0;
当SLEEPDEEP=0,SLEEPONEXIT=0,如果执行WFI,则立即进入"sleep模式",中断唤醒后,程序会继续执行main()中的其它语句;
退出睡眠方式是:中断;
当SLEEPDEEP=0,SLEEPONEXIT=0,如果执行WFE,则立即进入"sleep模式",唤醒后,程序会继续执行main()中的其它语句;
退出睡眠方式是:唤醒事件,包括中断;2)执行HAL_PWR_EnableSleepOnExit(),则令SLEEPONEXIT位置1;
若执行WFI或WFE,则立即进入"sleep模式";中断唤醒后,程序只执行"相应的中断服务程序",退出中断后,会再次进入"sleep模式",
因此,不再执行执行main()中的其它语句;
唤醒退出方式是:中断;3)执行HAL_PWR_EnableSEVOnPend(),则令SEVONPEND位置1;允许事件唤醒内核(包括中断唤醒),
在执行WFE指令前,需要先设置SEVONPEND=1,才可以使用事件唤醒,否则,只能使用中断唤醒,
但通过WFI进入的"sleep模式",即使设置SEVONPEND=1,事件也无法唤醒CPU核,不清楚原因?4)"stop模式"可以执行事件唤醒和中断唤醒。注意:在sleep模式中,所有的"IO引脚"和"run模式"保持相同的电平状态;
在进入睡眠前,需要配置好"相应的唤醒源",关闭不用的模块,如SysTick,以便CPU进入Sleep模式;
*/void EnterSLEEPMode_With_WFE(void);
void EnterSLEEPMode_With_WFI(void);
void EnterSLEEPMode_With_WFE_And_After_Interrupt(void);
void EnterSLEEPMode_With_WFI_And_After_Interrupt(void);//函数功能:中断或事件唤醒后,程序会继续执行main()中的其它语句
//通过WFE进入的"sleep模式",退出方式是:唤醒事件,也可以是中断
void EnterSLEEPMode_With_WFE(void)
{__HAL_RCC_PWR_CLK_ENABLE();//PWR时钟使能//这一句不能少,否则,不能进入"sleep模式"HAL_PWR_DisableSleepOnExit();//则令SLEEPONEXIT位置0;//如果执行WFE,则立即进入"sleep模式"HAL_PWR_EnableSEVOnPend();//当"SEVONPEND=1"时,允许事件唤醒内核(包括中断唤醒)//这一句不能少,否则,事件无法唤醒CPUHAL_PWR_EnterSLEEPMode(PWR_SLEEPENTRY_WFE);//令SLEEPDEEP=0,然后执行WFE,令CPU进入"sleep模式"
}//函数功能:中断唤醒后,程序会继续执行main()中的其它语句
//通过WFI进入的"sleep模式",退出方式是:只能是中断
void EnterSLEEPMode_With_WFI(void)
{__HAL_RCC_PWR_CLK_ENABLE();//PWR时钟使能//这一句不能少,否则,不能进入"sleep模式"HAL_PWR_DisableSleepOnExit();//则令SLEEPONEXIT位置0;//如果执行WFI,则立即进入"sleep模式"HAL_PWR_EnableSEVOnPend();//当"SEVONPEND=1"时,允许事件唤醒内核(包括中断唤醒)//这一句不能少,否则,事件无法唤醒CPUHAL_PWR_EnterSLEEPMode(PWR_SLEEPENTRY_WFI);//令SLEEPDEEP=0,然后执行WFI,令CPU进入"sleep模式"
}//函数功能:中断唤醒后,程序只执行"相应的中断服务程序",退出中断后,会再次进入"sleep模式";
//SLEEPONEXIT位置1,通过WFE进入的"sleep模式",退出方式是:只能是中断
void EnterSLEEPMode_With_WFE_And_After_Interrupt(void)
{__HAL_RCC_PWR_CLK_ENABLE();//PWR时钟使能//这一句不能少,否则,不能进入"sleep模式"HAL_PWR_EnableSleepOnExit();//则令SLEEPONEXIT位置1,若执行WFE,则立即进入"sleep模式";当有中断发生后,则执行完中断服务程序,会继续进入"sleep模式"HAL_PWR_EnterSLEEPMode(PWR_SLEEPENTRY_WFE);//令SLEEPDEEP=0,然后执行WFE,令CPU进入"sleep模式"
}//函数功能:中断唤醒后,程序只执行"相应的中断服务程序",退出中断后,会再次进入"sleep模式";
//SLEEPONEXIT位置1,通过WFI进入的"sleep模式",退出方式是:只能是中断
void EnterSLEEPMode_With_WFI_And_After_Interrupt(void)
{__HAL_RCC_PWR_CLK_ENABLE();//PWR时钟使能//这一句不能少,否则,不能进入"sleep模式"HAL_PWR_EnableSleepOnExit();//则令SLEEPONEXIT位置1,若执行WFI,则立即进入"sleep模式";当有中断发生后,则执行完中断服务程序,会继续进入"sleep模式"HAL_PWR_EnterSLEEPMode(PWR_SLEEPENTRY_WFI);//令SLEEPDEEP=0,然后执行WFI,令CPU进入"sleep模式"
}
#include "py32f0xx_hal.h"
#include "SystemClock.h"
#include "delay.h"
#include "LED.h"
#include "SystemClock.h"
#include "USART2.h"
#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()
#include "EXTI.h"
#include "SleepMode.h"const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
const char CPU_Run_REG[]="\r\nCPU run!\r\n";
int main(void)
{HSE_Config();
// HSI_Config();
// HAL_Init();//systick初始化delay_init();HAL_Delay(1000);USART2_Init(115200);
//PA0是为USART2_TX,PA1是USART2_RX
//中断优先级为0x01
//波特率为115200,数字为8位,停止位为1位,无奇偶校验,允许发送和接收数据,只允许接收中断,并使能串口printf("%s",CPU_Reset_REG);HAL_Delay(1000);printf("%s",CPU_Run_REG);MCU_LED_Init();HAL_SuspendTick();//systick中断关闭,防止systick中断唤醒EXTI12_Init();//将PA12引脚配置为外部中断引脚printf("SLEEP MODE!\n\n");EnterSLEEPMode_With_WFE();
// EnterSLEEPMode_With_WFI();
// EnterSLEEPMode_With_WFE_And_After_Interrupt();
// EnterSLEEPMode_With_WFI_And_After_Interrupt();__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_12);//清除外部事件标志位//清除"GPIO_PIN_12外部事件标志位"//当软件或者硬件产生上升沿/下降沿触发事件时,该位置位;NVIC_ClearPendingIRQ(EXTI4_15_IRQn);//清除EXTI4_15_IRQn中断源的中断标志位HAL_ResumeTick();//systick中断开启printf("WAKEUP OK!\n\n");while (1){HAL_Delay(500);MCU_LED_Toggle();printf("1234567890\r\n");}
}
事件唤醒:
//函数功能:将PA12引脚配置为外部事件引脚
void EXTI12_Init(void)
{GPIO_InitTypeDef GPIO_InitStructureure;__HAL_RCC_GPIOA_CLK_ENABLE(); //GPIOA时钟使能GPIO_InitStructureure.Pin = GPIO_PIN_12;//选择第12脚GPIO_InitStructureure.Pull = GPIO_PULLUP;//引脚上拉被激活GPIO_InitStructureure.Speed = GPIO_SPEED_FREQ_MEDIUM;//配置GPIO速度为中速GPIO_InitStructureure.Mode = GPIO_MODE_IT_FALLING;//配置为下降沿检测模式HAL_GPIO_Init(GPIOA, &GPIO_InitStructureure);//根据GPIO_InitStructureure结构变量指定的参数初始化GPIOA的外设寄存器//因为使用了GPIO_MODE_IT_FALLING,所以使能了外部中断线// HAL_NVIC_SetPriority(EXTI4_15_IRQn,0x0F,0);//EXTI4_15_IRQn表示外部中断线4~中断线15,EXTI4_15_IRQn//设置中断优先级为0x0F,0无意义,注意:0<=PreemptPriority<=3,值越大,表示中断优先级越低//Enable and set Button EXTI Interrupt to the lowest priority// HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);//EXTI4_15_IRQn表示外部中断线4~中断线15,EXTI4_15_IRQn//使能EXTI4_15_IRQn中断
}
中断唤醒
//函数功能:将PA12引脚配置为外部中断引脚
void EXTI12_Init(void)
{GPIO_InitTypeDef GPIO_InitStructureure;__HAL_RCC_GPIOA_CLK_ENABLE(); //GPIOA时钟使能GPIO_InitStructureure.Pin = GPIO_PIN_12;//选择第12脚GPIO_InitStructureure.Pull = GPIO_PULLUP;//引脚上拉被激活GPIO_InitStructureure.Speed = GPIO_SPEED_FREQ_MEDIUM;//配置GPIO速度为中速GPIO_InitStructureure.Mode = GPIO_MODE_IT_FALLING;//配置为下降沿检测模式HAL_GPIO_Init(GPIOA, &GPIO_InitStructureure);//根据GPIO_InitStructureure结构变量指定的参数初始化GPIOA的外设寄存器//因为使用了GPIO_MODE_IT_FALLING,所以使能了外部中断线HAL_NVIC_SetPriority(EXTI4_15_IRQn,0x03,0);//EXTI4_15_IRQn表示外部中断线4~中断线15,EXTI4_15_IRQn//设置中断优先级为0x03,0无意义,注意:0<=PreemptPriority<=3,值越大,表示中断优先级越低//Enable and set Button EXTI Interrupt to the lowest priorityHAL_NVIC_EnableIRQ(EXTI4_15_IRQn);//EXTI4_15_IRQn表示外部中断线4~中断线15,EXTI4_15_IRQn//使能EXTI4_15_IRQn中断
}
三、事件唤醒测试结果