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

news2025/1/6 18:41:09

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、代码

代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/656199.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

编译原理笔记(哈工大编译原理)

文章目录 前言概论语言与文法基本概念字母表串字母表与串的联系 文法语言推导和规约句型与句子语言与字母表 文法的分类 前言 说实话&#xff0c;我不是很想上这门课&#xff0c;确实没什么大用&#xff0c;虽然我觉得这门课学一学也挺好&#xff0c;但是我觉得弄8个大实验就真…

socket地址的通配符地址、环回地址

今天在写ServerSocket的时候&#xff0c;遇到了socket地址的通配符地址、环回地址。 package com.thb;import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket;public class ServerSocketMain {public static void main(String[] args) {try…

UI Tool Kit 使用

Unity 2021 已经把UIBuilder 内置了&#xff0c;项目组也打算 后续工具采用 toolkit来写&#xff0c;这边也是找了一下教程熟悉了一下。 UI 工具包 - Unity 手册 首先 先创建一个EditorWindow 会生成相应的C#&#xff0c;UXML,USS代码 默认会把显示的MenuItem代码生成&#xf…

记录--设计一个可选择不连续的时间范围的日期选择器

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 npm包&#xff1a;sta-datepicker效果图 需求 普通的时间选择器要么只能单选&#xff0c;要么只能选范围&#xff0c;不可以随意选择若干个时间&#xff0c;同时大多数现成的时间选择器选择结束会收起…

EasyExcel实战与笔记

概述 Excel导入导出是业务开发中非常常见的需求。本文记录一下如何快速入门使用EasyExcel&#xff0c;深度实战&#xff0c;以及遇到的问题。 入门 使用EasyExcel导入如下依赖即可&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactI…

java-代码生成器——有了代码生成器两个小时的工作量2分钟完成了

代码生成器 &#x1f942;代码生成器&#x1f33b;1. 第一步引用相关依赖&#x1f357;2. 第二步编写代码 CodeGet.java&#x1f969;3. 第三步运行查看结果&#x1f356;4. 第四步总结一下 &#x1f942;代码生成器 只需要创建好表的结构&#xff0c;代码生成器通过简单的配置…

Linux知识点 -- 进程控制(二)

Linux知识点 – 进程控制&#xff08;二&#xff09; 文章目录 Linux知识点 -- 进程控制&#xff08;二&#xff09;一、进程程序替换1.概念2.替换原理3.进程替换的操作4.使用exec函数执行自己写的程序5.使用exec函数执行其他语言的程序 二、编写一个简易的shell 一、进程程序替…

LeetCode 892. Surface Area of 3D Shapes【数组,数学】简单

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

KCC@北京启动,为一个城市做好开源!

KCC&#xff08;开源社城市社区&#xff09;北京区在6月12日正式成立&#xff0c;吸引了众多开源爱好者和技术开发者参与。现场举行的活动围绕 “为一个城市做好开源” 的话题展开讨论&#xff0c;包括开发者关系、开源背后的无用之用、开源在中国的变化、开源的困难与挑战以及…

OpenAI ChatGPT 使用示例

1.编程应用 1.1. 生成例子代码 ChatGPT帮助我们生产我们需要的例子代码。而且准确率很高。即使你不懂某一种语言也没关系&#xff0c;一定程度上较低了程序员的的门槛。 我有三组数据&#xff0c;第一组是星期一到星期五&#xff0c;第二组是这一天的具体时间&#xff0c;第三…

etcd 备份操作---马哥教育

etcd安装&#xff1a; mkdir -pv etcd-download-test tar -zxvf etcd-v3.4.4-linux-amd64.tar.gz -C etcd-download-test/ 编辑修改系统环境变量 /etc/profile export ETCD_HOME/tmp/etcd-download-test/etcd-v3.4.4-linux-amd64 export PATH$PATH:$JAVA_HOME/bin:$ETCD_HOM…

html实现好看的个人介绍,个人主页模板2(附源码)

文章目录 1.设计来源1.1 主界面1.2 关于我界面1.3 项目演示界面1.4 联系我界面 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目录 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/131257976 html实现好看的个人…

老胡的周刊(第095期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 tabby[2] 自托管的 AI 编码助手&#xff0c;…

230617安装SqlServer2017Express后,再安装一个SqlServer2017ExpressAdvanced

230616安装SqlServer2017Express 下载地址 选择语言 Microsoft SQL Server 2017 Express 下载地址: 简体中文 感谢下载 Microsoft SQL Server 2017 Express 获得下载软件 我将下载的文件的名称加上了SHA256值, 一长串 是一个 .exe 的自解压文件, 双击后,默认解压到同根文件夹…

计组期末模拟(补充)

单选题 2-1&#xff08;本题考查课程目标2&#xff09; 某计算机有 16 个通用寄存器&#xff0c;采用 32 位定长指令字&#xff0c;操作码字段&#xff08;含寻址方式位&#xff09;为 8 位&#xff0c;Store 指令的源操作数和目的操作数分别采用寄存器直接寻址和基址寻址方式…

PHP intval()函数详解,intval()函数漏洞原理及绕过思路

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 intval 一、进制自动转换二、转换数组三、转换小数…

#systemverilog# 之 event region 和 timeslot 仿真调度(三)Verdi 辅助查看

前面的几篇文章,我们对SV仿真调度进行了理论分析和实战演练。那么工具厂商,对该类问题有没有提供相应的支持。这个应该是肯定的。因为我们知道,SV只是出于定义标准的角度,规定了仿真调度事件原理。但是具体实施细节,应是每家EDA仿真工具厂商根据自家的软件开发算法而定的。…

MySQL - 第3节 - MySQL数据类型

1.数据类型的作用 数据类型的作用&#xff1a; • 决定了存储数据时应该开辟的空间大小。 • 决定了如何识别一个特定的二进制序列。 • 决定了数据的取值范围。 2.数据类型分类 注&#xff1a;MySQL本身是不支持bool类型的&#xff0c;当把一个数据设置成bool类型时&#xff0…

NetMock 简介:简化 Java、Android 和 Kotlin 多平台中的 HTTP 请求测试

NetMock 简介&#xff1a;简化 Java、Android 和 Kotlin 多平台中的 HTTP 请求测试 NetMock可让我们摆脱在测试环境中模拟请求和响应的复杂性。 NetMock是一个功能强大、用户友好的库&#xff0c;旨在简化模拟HTTP请求和响应的过程。 对开发者来说&#xff0c;测试HTTP请求经…