细说STM32F407单片机电源低功耗StopMode模式及应用示例
目录
一、停止模式基础知识
1、进入停止模式
2、停止模式的状态
3、退出停止模式
4、SysTick定时器的影响
二、停止模式应用示例
1、示例功能和CubeMX项目配置
(1)时钟
(2)RTC
(3)ADC1
(4) NVIC
(5)DEBUG、LED1、USART6、CodeGenerator
2、软件设计
(1)KEYLED
(2)main.h
(3)main.c
3、运行并调试
一、停止模式基础知识
1、进入停止模式
用户可以通过执行WFI指令或WFE指令进入停止模式。进入停止模式之前,用户需要将Cortex-M4F系统控制寄存器SCR的SLEEPDEEP位置1,内部调压器可以设置为正常运行或低功耗模式。函数HAL_PWR_EnterSTOPMode()用于进入停止模式,其源代码如下:
函数HAL_PWR_EnterSTOPMode()用于进入停止模式,其源代码如下:
void HAL_PWR_EnterSTOPMode(uint32_t Regulator,uint8_t STOPEntry)
{/*Check the parameters */assert_param(IS_PWR_REGULATOR(Regulator));assert_param(IS_PWR_STOP_ENTRY(STOPEntry));/*设置调压器的模式:根据参数Regulator设置PDDS位和LPDS位*/MODIFY_REG(PWR->CR,(PWR_CR_PDDS I PWR_CR_LPDS),Regulator);/*将Cortex系统控制寄存器SCR的SLEEPDEEP位置1*/SET_BIT(SCB->SCR,((uint32_t)SCB_SCR_SLEEPDEEP_Msk));/*Select Stop mode entry*/if(STOPEntry == PWR_STOPENTRY_WFI){/*Request Wait For Interrupt */__WFI();}else{/*Request Wait For Event */__SEV();__WFE();__WFE();}/*唤醒后,将SLEEPDEEP位清零*/CLEAR_BIT(SCB->SCR,((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
}
参数Regulator用于表示调压器在停止模式下的工作方式,取值为宏定义常量PWR_MAINREGULATOR_ON(调压器正常运行)或PWR_LOWPOWERREGULATOR_ON(调压器处于低功耗模式)。
参数SLEEPEntry表示用何种指令进入睡眠模式,WFI或WFE指令。其取值为宏定义常量PWR_SLEEPENTRY_WFI或PWR_SLEEPENTRY_WFE。
函数HAL_PWR_EnterSTOPMode()在进入停止模式之前,将Cortex-M4F系统控制寄存器SCR的SLEEPDEEP位置1,被唤醒后再将SLEEPDEEP位清零。
特别地,要进入停止模式,所有EXTI线的中断挂起标志都必须清零,否则,将忽略进入停止模式的操作,而继续执行程序。
在停止模式下,可以保持或关闭Flash的电源,在进入停止模式之前,可以使用以下两个函数进行设置。
HAL_PWREX_EnableFlashPowerDown(); //关闭Flash的电源
HAL_PWREx_DisableFlashPowerDown(); //不关闭Flash的电源
2、停止模式的状态
进入停止模式后,系统的状态如下。
- CPU的时钟关闭,CPU停止运行,也就是程序暂停。
- 所有1.2V域外设的时钟停止,外设停止工作。
- ADC和DAC不会自动停止工作,需要编程使其停止。
- 1.2V调压器开启或处于低功耗状态,所有寄存器、SRAM的内容保留。
- Flash处于正常模式或掉电模式。
- HSI振荡器和HSE振荡器关闭。
3、退出停止模式
如果使用WFI指令进入停止模式,所有配置为中断模式的EXTI线都可以唤醒系统。由中断唤醒后,先执行中断的ISR,然后执行WFI指令后面的程序。
如果使用WFE指令进入停止模式,所有配置为事件模式的EXTI线都可以唤醒系统,唤醒后执行WFE后面的程序。
EXTI线共23根,EXTI线0:15对应于外部引脚中断,EXTI线16:22对应一些内部事件,如RTC闹钟事件、RTC周期唤醒事件等。
从停止模式唤醒时,系统有一定的唤醒延迟时间,包括以下几个时间。
- HSI振荡器的启动时间。系统将重新启动HSI振荡器,并且将HSI作为HCLK的时钟源。对STM32F407来说,HSI频率为16MHz,使用HSI作为时钟源的HCLK最高频率为16MHz。如果需要系统从停止模式唤醒后使用更高频率的HCLK,需要重新配置系统时钟。
- 如果调压器处于低功耗模式,需要从低功耗模式恢复到正常模式的时间。
- 若Flash处于掉电模式,需要从掉电模式恢复到正常模式的时间。
在停止模式下,如果调压器处于低功耗模式、Flash处于掉电模式,则可以降低停止模式的功耗,但这同时也会增加唤醒延迟。
4、SysTick定时器的影响
MCU进入停止模式后,将只会由EXTI中断或事件唤醒,而不受SysTick定时器的影响。此外,在进入停止模式后,所有的1.2V域外设都会停止工作,SysTick定时器其实也停止了。
二、停止模式应用示例
本文将创建一个示例项目,测试系统的STOP模式。继续使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0。一些设置参考本文作者的其他文章。
参考文章:细说STM32F407单片机电源低功耗SleepMode模式及应用示例-CSDN博客 https://wenchm.blog.csdn.net/article/details/145226004
1、示例功能和CubeMX项目配置
本文演示MCU的停止模式。示例的功能和操作流程如下。
- 在主程序的while循环里,让MCU进入停止模式。
- 使用RTC的周期唤醒中断,使MCU从停止模式唤醒,RTC唤醒周期为5s。
- MCU从停止模式唤醒后,进行一次轮询方式ADC转换。
(1)时钟
禁用HSE,这样做很重要,因为不这样做,依旧设置外部时钟的话,系统将不能清空EXTI的中断线标志位。将HSI直接作为HCLK时钟源,HCLK设置为16MHz。因为MCU从停止模式唤醒后,自动使用HSI作为SYSCLK时钟源,所以,如果要使用HSE或更高频率的HCLK,需要重新配置系统时钟。本示例在系统唤醒后,不再配置HCLK时钟频率,故正常运行时也使用HSI作为HCLK时钟源。

(2)RTC
并使用LSE作为RTC的时钟源。开启RTC的周期唤醒功能,
并设置唤醒时钟为1Hz信号,唤醒计数值为4。RTC的周期唤醒使用的是EXTI线22中断,在NVIC中开启RTC周期唤醒中断,设置其抢占优先级为1。这样设置后,每5s发生一次EXTI线22中断。


(3)ADC1
启用ADC1的内部参考电压通道,设置为12位精度、右对齐、软件触发转换。ADC1的参数设置结果如图。

(4) NVIC

(5)DEBUG、LED1、USART6、CodeGenerator
同参考文章。
2、软件设计
(1)KEYLED
本示例工程继续引用KEYLED文件夹中的keyled.h,详见参考文章。
(2)main.h
声明一个函数,用于EXTI线清零。
/* USER CODE BEGIN Private defines */
void EXTI_ClearITPendingBit();
/* USER CODE END Private defines */
(3)main.c
/* USER CODE BEGIN Includes */
#include "keyled.h"
#include <stdio.h> //用到函数sprintf()
#include <string.h> //用到函数strlen()
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */printf("Demo22_2_StopMode:Test Stop Mode.\r\n");printf("Wake up by RTC every 5s.\r\n");//如果配置了FSMC//HAL_PWREx_EnableFlashPowerDown(); //在停止模式下关闭Flash电源//HAL_PWREx_DisableFlashPowerDown(); //不关闭Flash电源/* USER CODE END 2 */
/* USER CODE BEGIN 3 */LED1_OFF(); //LED1熄灭//以下3种清零除EXTI线pending位的方法都是正确的,确保能进入STOP模式//EXTI->PR = 0; //将EXTI线的pending位清零EXTI->PR = EXTI_PR_PR0 << 22; //将EXTI线22的pending位清零//EXTI_ClearITPendingBit(EXTI_PR_PR22); //将EXTI线22的pending位清零//进入停止模式, WFI指令进入HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);//RTC周期唤醒中断(EXTI22)唤醒系统LED1_ON();HAL_ADC_Start(&hadc1); //使能ADC1并开始转换,内部通道参考电压if (HAL_ADC_PollForConversion(&hadc1,200) == HAL_OK){uint32_t val = HAL_ADC_GetValue(&hadc1) & 0x0000FFFF; //12位数uint32_t Volt = 3300*val; //单位:mVVolt = Volt>>12; //除以2^12printf("ADC Voltage(mV) = %ld\r\n",Volt);}HAL_ADC_Stop(&hadc1); //停止ADC1HAL_Delay(500); //消除按键抖动影响,并且使LED1亮500ms}/* USER CODE END 3 */
在进入while循环之前,调用了函数HAL_PWREx_EnableFlashPowerDown(),这可以在MCU进入停止模式后,关闭Flash存储器的电源,进一步降低功耗。也可以不关闭Flash存储器电源,也就是调用函数HAL_PWREx_DisableFlashPowerDown()(可选)。
在while循环里,调用函数HAL PWR EnterSTOPMode()使系统进入停止模式。必须在所有EXTI线中断的挂起标志位清零的情况下,才能进入停止模式。为此,直接将外部中断挂起标志寄存器PR的内容清零,即执行语句:
EXTI->PR =0;
进入停止模式后,CPU停止运行,程序暂停,所有外设停止工作,但RTC仍能正常工作。停止模式可以由任意EXTI线的中断或事件唤醒,RTC的周期唤醒中断是EXTI线22。本示例中设置的RTC唤醒周期是5s,所以,在发生RTC周期唤醒中断时系统会被唤醒,但是会先执行RTC中断的ISR,也就是会执行RTC周期唤醒回调函数HAL_RTCEx_WakeUpTimerEventCallback(),这个回调函数里读取RTC当前时间并显示在串口助手上。RTC中断的ISR退出后,再继续执行WFI指令后面的程序。后面的程序用轮询方式进行一次ADC转换,将结果显示在串口助手上。ADC转换结束后停止,然后MCU又进入停止模式。
/* USER CODE BEGIN 4 */
// RTC 周期唤醒中断回调函数
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{RTC_TimeTypeDef sTime;RTC_DateTypeDef sDate;if (HAL_RTC_GetTime(hrtc,&sTime,RTC_FORMAT_BIN) == HAL_OK){HAL_RTC_GetDate(hrtc,&sDate,RTC_FORMAT_BIN);uint8_t str[30];sprintf((char *)str,"%2d:%2d:%2d",sTime.Hours,sTime.Minutes,sTime.Seconds);//HAL_UART_Transmit(&huart6,str,strlen ((const char *)(str)),200);printf("RTC current time: %s\r\n",str);}
}//清除EXTI线[0:22]的Pending register
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
{/* Check the parameters */assert_param(IS_EXTI_LINE(EXTI_Line));EXTI->PR = EXTI_Line;
}int __io_putchar(int ch)
{HAL_UART_Transmit(&huart6,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END 4 */
3、运行并调试
运行时会发现:每隔5s串口助手上刷新显示一次RTC时间和ADC转换结果,LED1点亮500ms后熄灭。
停止模式比较适合于需要周期性唤醒,执行完一些操作后又进入低功耗模式的应用。例如,网络化的温度监测,可能每隔60s才需要测量一次数据并通过网络发送出去,使用周期唤醒的停止模式就可以大大降低功耗。 
在CubeMX里可以对本示例进行功耗计算。因为使用了16MHz的HCLK,RUN模式下的耗电流是8.78mA,STOP模式下的耗电流是280μA。如果还选用3400mAh的锂电池供电,如果一个序列中RUN模式持续10ms,STOP模式持续100ms,电池可以用4月12天10小时;若修改为STOP模式持续1000ms,其他参数不变,电池可以用1年28天,可见降低功耗的效果是非常明显的。

相关文章:
细说STM32F407单片机电源低功耗StopMode模式及应用示例
目录 一、停止模式基础知识 1、进入停止模式 2、停止模式的状态 3、退出停止模式 4、SysTick定时器的影响 二、停止模式应用示例 1、示例功能和CubeMX项目配置 (1)时钟 (2)RTC (3)ADC1 …...
PHP语言的循环实现
PHP语言的循环实现详解 在当今的编程世界中,循环是一种不可或缺的基本构造,它使得我们能够重复执行某些操作,极大地提高了代码的复用性和可读性。在PHP语言中,循环的种类以及使用方式繁多,本文将全面探讨PHP中的循环实…...
求两个矩阵的乘积
求两个矩阵的乘积 分数 15 全屏浏览 切换布局 作者 C课程组-hwr-zy 单位 浙江大学 输入三个正整数m,l,n(0<m,n,l<10),再输入两个的矩阵a(mxl)和b(lxn)。要求把a和…...
警惕IDEA 2024版重大Bug问题:LomBok失效、Gradle冲突、Spring Boot启动错误
一直以来我认为工具类的软件是越新越好,因为工具代表着一定的先进性;但是IDEA 2024好好的给我上了一课,比如lombok 不起作用、比如Spring Boot 3.4.x 启动报错、再比如MyBatis log plus冲突、再比如Gradle插件冲突. 一、Lombok 失效问题 请不…...
Go语言的正则表达式
Go语言的正则表达式:深度解析与应用实例 引言 正则表达式(Regular Expression,简称 regex)是一种用于匹配字符串的强大工具,广泛应用于文本处理、数据验证、解析和提取等场景。Go语言作为一种现代编程语言࿰…...
通过ssh连接debian
使用方法 ssh usernameipaddress [inputpasswd]root用户默认无法由ssh连接, 可以通过修改配置 sudo vim /etc/ssh/sshd_config去掉PermitRootLogin前的‘#’,并修改为 PermitRootLogin yes 重启sshd服务 sudo systemctl restart sshd参考 https://linuxconfig.or…...
计算机创造的奇迹——C语言
一.简介 C语言是一种较早的程序设计语言,诞生于1972年的贝尔实验室。1972 年,Dennis Ritchie 设计了C语言,它继承了B语言的许多思想,并加入了数据类型的概念及其他特性。 尽管C 语言是与 UNIX 操作系统一起被开发出来的ÿ…...
磁盘阵列服务器和普通服务器的区别
磁盘阵列服务器(RAID Server)和普通服务器在多个方面存在显著区别。以下是它们的主要区别: 1. 存储架构 磁盘阵列服务器 RAID 技术:使用 RAID(冗余独立磁盘阵列)技术,将多个硬盘组合成一个逻…...
搭建一个人脸识别pipeline
文章目录 概要入门所需设置你的开发环境人脸识别的工作原理数据加载和预处理建立你的人脸识别模型评估你的模型总结概要 人脸识别已发展成为一项关键技术,现已嵌入从安全系统到社交媒体平台等各个领域。在本文中,我们将逐步指导您在短短 30 分钟内使用 Python 和机器学习创建…...
Docker 之mysql从头开始——Docker下mysql安装、启动、配置、进入容器执行(查询)sql
一、Docker 之mysql安装配置 步骤一:拉取镜像 1. 查看是否包含已安装的mysql。 docker images | grep mysql 2. 如上图所示,我们有mysql镜像,所以不必对mysql镜像进行拉取,如若没有上图中的惊喜,使用如下命令进行拉取…...
LeetCodeHOT100:60. n个骰子的点数、4. 寻找两个正序数组的中位数
LeetCodeHOT100: 剑指 Offer 60. n个骰子的点数4. 寻找两个正序数组的中位数96. 不同的二叉搜索树 剑指 Offer 60. n个骰子的点数 题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率…...
apisix的authz-casbin
目录 1、apisix的auth-casbin官方介绍 2、casbin介绍和使用 2.1基本知识: 2.2使用例子 3、配置插件 4、postman调用 5、auth-casbin的坑 1、apisix的auth-casbin官方介绍 authz-casbin | Apache APISIX -- Cloud-Native API Gateway 2、casbin介绍和使用 c…...
数学基础 --线性代数之理解矩阵乘法
理解矩阵乘法的解析 矩阵乘法(Matrix Multiplication)是线性代数中的核心操作之一。在数学、几何和工程实际中,它不仅是一种代数运算规则,还承载着丰富的几何和映射意义。本文将从多个角度深入解析矩阵乘法,帮助读者理…...
TCP Window Full是怎么来的
wireshark查看包时,会看到TCP Window Full,总结下它的特点: 1. Sender会显示 TCP Window Full 2. “Sender已发出,但,Receiver尚未ack的字节”,即Sender的 bytes in flights 3. Sender的 bytes in fligh…...
【22】Word:小李-高新技术企业政策❗
目录 题目 NO1.2 NO3 NO4 NO5.6 NO7.8 NO9.10 若文章中存在删除空白行等要求,可以到最后来完成。注意最后一定要检查此部分!注意:大多是和事例一样即可,不用一摸一样,但也不要差太多。 题目 NO1.2 F12Fn&a…...
大数据,Hadoop,HDFS的简单介绍
大数据 海量数据,具有高增长率、数据类型多样化、一定时间内无法使用常规软件工具进行捕捉、管理和处理的数据集 合 大数据的特征: 4V Volume : 巨大的数据量 Variety : 数据类型多样化 结构化的数据 : 即具有固定格式和有限长度的数据 半结构化的数据 : 是…...
Python预训练视觉和大语言模型——精彩试读
基础模型永久改变了机器学习。从BERT到ChatGPT,从CLIP到Stable Diffusion,当数十亿个参数、大数据集与成百上千个GPU相结合时,结果刷新了纪录。《Python预训练视觉和大语言模型》呈现的真知灼见和示例代码将帮你在AWS和Amazon SageMaker上从头…...
html全局遮罩,通过websocket来实现实时发布公告
1.index.html代码示例 <div id"websocket" style"display:none;position: absolute;color:red;background-color: black;width: 100%;height: 100%;z-index: 100; opacity: 0.9; padding-top: 30%;padding-left: 30%; padding-border:1px; "onclick&q…...
Vue3初学之Element-plus Form表单
1.使用 el-form 组件 el-form 是一个表单容器,可以包含多个 el-form-item,每个 el-form-item 包裹具体的表单控件,如输入框、选择器、日期选择器等。 <template><el-form :model"form" label-width"120px">…...
第14章:Python TDD应对货币类开发变化(一)
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
