Nucleo-F411RE (STM32F411)LL库体验 7 - 低功耗(睡眠、待机)

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,显示当前设备信息,如下:
Nucleo-F411RE (STM32F411)LL库体验 7 - 低功耗(睡眠、待机)_第1张图片
输入 pwr --sleep,灯会快速函数,然后进入睡眠。
Nucleo-F411RE (STM32F411)LL库体验 7 - 低功耗(睡眠、待机)_第2张图片
输入pwr --stop 进入停机模式
在这里插入图片描述
输入 pwr --standby 进入待机模式,但是这里的唤醒可不是蓝色按键了,而是PA0,待机后,将PA0接3.3v即可唤醒。
Nucleo-F411RE (STM32F411)LL库体验 7 - 低功耗(睡眠、待机)_第3张图片
Nucleo-F411RE (STM32F411)LL库体验 7 - 低功耗(睡眠、待机)_第4张图片

另外,睡眠不能在中断函数里处理,shell串口的收数据是在中断里,所以不能解析到命令直接进入sleep mode,这里设置了一个变量,main的while循环里去进入sleep mode。

#include "extend_shell.h"
#include "power_mode.h"
#include "shell_port.h"
#include 
#include 
#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、代码

代码下载

你可能感兴趣的:(Nucleo-F411RE,stm32,嵌入式硬件,单片机)