Nucleo-F411RE (STM32F411)LL库体验 7 - 低功耗(睡眠)
1、简述
F411有三种模式 Sleep mode、stop mode 、standby mode。
其中SleepMode 、Stop Mode 可选择WFI 以及WFE,两者的区别在于,前者任何中断都能唤醒,后者只能是Wakeup Event才能唤醒。
唤醒时接着进入睡眠处的代码继续执行。
借助之前的letter shell,我们添加pwr命令,输入pwr --sleep 进入sleep mode,
输入pwr --stop 进入stop mode。每次进入睡眠跟唤醒之前,灯会快速闪烁。
这里选择进入__WFI,承接前一章,我们将Blue Button设置为了中断,mcu进入睡眠后,我们按一下按键,可唤醒mcu。
2、按键中断设置
前一章讲过,这里只把重要代码贴一下。
/**
* @brief This function configures EXTI Line as Push-Button
* @note Peripheral configuration is minimal configuration from reset values.
* @param None
* @retval None
*/
static void BOARD_UserButtonConfigureEXTI()
{
/* -1- GPIO Config */
/* Enable GPIO Clock (to be able to program the configuration registers) */
USER_BUTTON_GPIO_CLK_ENABLE();
/* Configure IO */
LL_GPIO_SetPinMode(USER_BUTTON_GPIO_PORT, USER_BUTTON_PIN, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinPull(USER_BUTTON_GPIO_PORT, USER_BUTTON_PIN, LL_GPIO_PULL_NO);
/* -2- Connect External Line to the GPIO*/
USER_BUTTON_SYSCFG_SET_EXTI();
/*-3- Enable a falling trigger EXTI line 13 Interrupt */
USER_BUTTON_EXTI_LINE_ENABLE();
USER_BUTTON_EXTI_FALLING_TRIG_ENABLE();
/*-4- Configure NVIC for EXTI15_10_IRQn */
NVIC_EnableIRQ(USER_BUTTON_EXTI_IRQn);
NVIC_SetPriority(USER_BUTTON_EXTI_IRQn,0);
}
定义:
/**
* @brief Key push-button
*/
#define USER_BUTTON_PIN LL_GPIO_PIN_13
#define USER_BUTTON_GPIO_PORT GPIOC
#define USER_BUTTON_GPIO_CLK_ENABLE() LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC)
#define USER_BUTTON_EXTI_LINE LL_EXTI_LINE_13
#define USER_BUTTON_EXTI_IRQn EXTI15_10_IRQn
#define USER_BUTTON_EXTI_LINE_ENABLE() LL_EXTI_EnableIT_0_31(USER_BUTTON_EXTI_LINE)
#define USER_BUTTON_EXTI_FALLING_TRIG_ENABLE() LL_EXTI_EnableFallingTrig_0_31(USER_BUTTON_EXTI_LINE)
#define USER_BUTTON_SYSCFG_SET_EXTI() do { \
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); \
LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTC, LL_SYSCFG_EXTI_LINE13); \
} while(0)
#define USER_BUTTON_IRQHANDLER EXTI15_10_IRQHandler
中断处理函数,唤醒睡眠用
/**
* @brief This function handles external line 13 interrupt request.
* @param None
* @retval None
*/
void USER_BUTTON_IRQHANDLER(void)
{
/* Manage Flags */
if(LL_EXTI_IsActiveFlag_0_31(USER_BUTTON_EXTI_LINE) != RESET)
{
LL_EXTI_ClearFlag_0_31(USER_BUTTON_EXTI_LINE);
}
if (LL_GPIO_IsInputPinSet(USER_BUTTON_GPIO_PORT,USER_BUTTON_PIN) == 0)
{
printf("key press\r\n");
}
}
3、sleepMode 、StopMode、StandbyMode
#include "power_mode.h"
/**
* @brief Function to configure and enter in STOP_MAINREGU Mode.
* @param None
* @retval None
*/
void EnterSTOP_MAINREGUMode(void)
{
/** Request to enter STOP_MAINREGU mode
* Following procedure describe in STM32F4xx Reference Manual
* See PWR part, section Low-power modes, STOP_MAINREGU mode
*/
/* Set STOP_MAINREGU mode when CPU enters deepsleep */
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU);
/* Set SLEEPDEEP bit of Cortex System Control Register */
LL_LPM_EnableDeepSleep();
/* Request Wait For Interrupt */
__WFI();
}
void Enter_SleepMode(void)
{
/* Set SLEEPDEEP bit of Cortex System Control Register */
LL_LPM_EnableDeepSleep();
/* Request Wait For Interrupt */
__WFI();
}
void EnterStandbyMode(void)
{
/* Disable all used wakeup sources */
LL_PWR_DisableWakeUpPin(LL_PWR_WAKEUP_PIN1);
/* Clear all wake up Flag */
LL_PWR_ClearFlag_WU();
/* Enable wakeup pin */
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN1);
/** Request to enter STANDBY mode
* Following procedure describe in STM32F4xx Reference Manual
* See PWR part, section Low-power modes, Standby mode
*/
/* Set STANDBY mode when CPU enters deepsleep */
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
/* Set SLEEPDEEP bit of Cortex System Control Register */
LL_LPM_EnableDeepSleep();
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM)
__force_stores();
#endif
/* Request Wait For Interrupt */
__WFI();
}
4、Letter Shell命令添加
这里用了linux的getopt_long函数来解析参数,这个比较常用的,如果不明白,请百度。
输入pwr -I,显示当前设备信息,如下:
输入 pwr --sleep,灯会快速函数,然后进入睡眠。
输入pwr --stop 进入停机模式
输入 pwr --standby 进入待机模式,但是这里的唤醒可不是蓝色按键了,而是PA0,待机后,将PA0接3.3v即可唤醒。
另外,睡眠不能在中断函数里处理,shell串口的收数据是在中断里,所以不能解析到命令直接进入sleep mode,这里设置了一个变量,main的while循环里去进入sleep mode。
#include "extend_shell.h"
#include "power_mode.h"
#include "shell_port.h"
#include <stdio.h>
#include <string.h>
#include "getopt.h"
volatile uint8_t blinkMode = 200;
volatile uint8_t sleepMode = 0;
void PWR_ShowUsage(void)
{
printf("Usage:\r\n");
printf(" pwr (-h | --help)\r\n");
printf(" pwr (-i | --info)\r\n");
printf(" pwr (--sleep) enter sleep mode \r\n");
printf(" pwr (--stop) enter stop mode \r\n");
printf(" pwr (--standby) enter standby mode \r\n");
}
void PWR_ShowInfomation(void)
{
LL_RCC_ClocksTypeDef rccClock;
LL_RCC_GetSystemClocksFreq(&rccClock);
printf("Nucleo-F411RE Info:\r\n");
printf(" Version : %s %s\r\n",__DATE__,__TIME__);
printf(" System Clock : %ld\r\n",rccClock.SYSCLK_Frequency);
printf(" AHB Clock : %ld\r\n",rccClock.HCLK_Frequency);
printf(" APB1 Clock : %ld\r\n",rccClock.PCLK1_Frequency);
printf(" APB2 Clock : %ld\r\n",rccClock.PCLK2_Frequency);
}
int PWR_Control(int argc,char *argv[])
{
int c;
int longindex = 0;
const char short_options[] = "hi";
const struct option long_options[] =
{
{"help", 0, NULL, 'h'},
{"info", 0, NULL, 'i'},
{"sleep", 0, NULL, 1},
{"stop", 0, NULL, 2},
{"standby", 0, NULL, 3},
{NULL, 0, NULL, 0},
};
if (argc == 1)
{
/* goto the help */
PWR_ShowUsage();
return 0;
}
/* init 0 */
optind = 0;
opterr = 0;
/* parse */
do
{
/* parse the args */
c = getopt_long(argc, argv, short_options, long_options, &longindex);
switch (c)
{
case 'h'/* constant-expression */:
/* code */
PWR_ShowUsage();
return 0;
case 'i':
PWR_ShowInfomation();
break;
case 1: /* for sleep mode */
printf("Now enter Sleep Mode\r\n");
sleepMode = 1;
break;
case 2: /* for sleep mode */
printf("Now enter Stop Mode\r\n");
sleepMode = 2;
break;
case 3: /* for sleep mode */
sleepMode = 3;
printf("Now enter Standby Mode\r\n");
break;
default:
break;
}
}while (c != -1);
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), pwr, PWR_Control, PWR_Control);
main函数:
#include "main.h"
#include "board_init.h"
#include "clock_init.h"
#include "stdio.h"
#include "systick.h"
#include "power_mode.h"
#include "shell_port.h"
#include "extend_shell.h"
void LED_Blinking_5s(void)
{
uint32_t i = 0;
/* Toggle IO in during 5s (25*200ms) */
for(i = 0; i < 25; i++)
{
LL_GPIO_TogglePin(LED2_GPIO_PORT, LED2_PIN);
BOARD_Delay1Ms(50);
}
}
void Configure_PWR(void)
{
/* Enable Power Clock */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
/* Check if the system was resumed from StandBy mode */
if (LL_PWR_IsActiveFlag_SB() != 0)
{
/* Clear Standby flag */
LL_PWR_ClearFlag_SB();
/* Change LED speed to SLOW to indicate exit from standby mode */
printf("mcu the system was resumed from StandBy mode \r\n");
}
/* Check and Clear the Wakeup flag */
if (LL_PWR_IsActiveFlag_WU() != 0)
{
LL_PWR_ClearFlag_WU();
}
}
int main(void)
{
BOARD_Init();
Configure_PWR();
User_Shell_Init();
while (1)
{
if (sleepMode == 0)
{
LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
}
else if (sleepMode == 1)
{
sleepMode = 0;
LED_Blinking_5s();
LED_OFF();
Enter_SleepMode();
BOARD_Init();
LED_Blinking_5s();
printf("Now From Sleep Mode\r\n");
}
else if (sleepMode == 2)
{
sleepMode = 0;
LED_Blinking_5s();
LED_OFF();
EnterSTOP_MAINREGUMode();
BOARD_Init();
LED_Blinking_5s();
printf("Now From Stop Mode\r\n");
}
else if (sleepMode == 3)
{
sleepMode = 0;
LED_Blinking_5s();
LED_OFF();
EnterStandbyMode();
}
/* Insert delay 250 ms */
BOARD_Delay1Ms(blinkMode);
}
}
5、代码
代码下载