当前位置: 首页 > news >正文

STM32F10x进入低功耗模式

STM32F10x进入低功耗模式

目录

  • STM32F10x进入低功耗模式
    • 1 低功耗模式简介
    • 2 睡眠模式详解
    • 3 停止模式详解
    • 4 待机模式详解
    • 5 示例代码
      • 5.1 标准库函数定义
      • 5.2 进入低功耗模式参考代码
    • 结束语

1 低功耗模式简介

在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。

STM32F10x有三种低功耗模式:
1、睡眠模式
Cortex-M3内核停止,所有外设包括Cortex™-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行
2、停止模式
所有的时钟都已停止
3、待机模式
1.8V电源关闭(CPU核心区域)

低功耗模式一览:
在这里插入图片描述
STM32电源框图:
在这里插入图片描述

此外,在运行模式下,可以通过以下方式中的一种降低功耗:
1、降低系统时钟。
2、关闭APB和AHB总线上未被使用的外设时钟。

2 睡眠模式详解

通过执行WFI或WFE指令可以进入睡眠状态。根据Cortex™-M3系统控制寄存器中的SLEEPONEXIT位的值,有两种选项可用于选择睡眠模式进入机制:
1、SLEEP-NOW:如果SLEEPONEXIT位被清除,当WFI或WFE被执行时,微控制器立即进入睡眠模式。
2、SLEEP-ON_EXIT:如果SLEEPONEXIT位被置位,系统从最低优先级的中断处理程序中退出时,微控制器就立即进入睡眠模式。

SLEEP-NOW模式一览:
在这里插入图片描述
SLEEP-ON_EXIT模式一览:
在这里插入图片描述

3 停止模式详解

停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。
此时在1.8V供电区域的的所有时钟都被停止,PLL、HSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。

停止模式进入和退出的方法如下:
在这里插入图片描述
进入停止模式:
在停止模式下,通过设置电源控制寄存器(PWR_CR)的LPDS位使内部调节器进入低功耗模式,能够降低更多的功耗。
需要注意:
1、如果正在进行闪存编程,直到对内存访问完成,系统才进入停止模式。
2、如果正在进行对APB的访问,直到对APB访问完成,系统才进入停止模式。
3、在进入停止模式前,如果一些外设没有被关闭,那么外设仍然消耗电流,如串口、ADC、DAC等。

退出停止模式:
通过中断或者唤醒事件可以退出停止模式。
需要注意:
1、退出停止模式后,HSI RC振荡器被默认选为系统时钟。
2、当电压调节器处于低功耗模式下,当系统从停止模式退出时,将会有一段额外的启动延时。如果在停止模式期间保持内部调节器开启,则退出启动时间会缩短,但相应的功耗会增加。

4 待机模式详解

待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。

待机模式进入和退出的方法如下:
在这里插入图片描述

进入待机模式:
进入待机模式需要做到以下几点:
1、设置Cortex-M3系统控制寄存器中的SLEEPDEEP位。
2、清除电源控制寄存器(PWR_CR)中的PDDS位。
3、通过设置PWR_CR中LPDS位选择电压调节器的模式。

退出待机模式:
当一个外部复位(NRST引脚)、IWDG复位、WKUP引脚上的上升沿或RTC闹钟事件的上升沿发生时,微控制器从待机模式退出。从待机唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位。
从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚、读取复位向量等)。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。

5 示例代码

5.1 标准库函数定义

睡眠模式标准库函数代码:

static __INLINE  void __WFI()                     { __ASM ("wfi"); }
static __INLINE  void __WFE()                     { __ASM ("wfe"); }

停机模式标准库函数代码:

/*** @brief  Enters STOP mode.* @param  PWR_Regulator: specifies the regulator state in STOP mode.*   This parameter can be one of the following values:*     @arg PWR_Regulator_ON: STOP mode with regulator ON*     @arg PWR_Regulator_LowPower: STOP mode with regulator in low power mode* @param  PWR_STOPEntry: specifies if STOP mode in entered with WFI or WFE instruction.*   This parameter can be one of the following values:*     @arg PWR_STOPEntry_WFI: enter STOP mode with WFI instruction*     @arg PWR_STOPEntry_WFE: enter STOP mode with WFE instruction* @retval None*/
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
{uint32_t tmpreg = 0;/* Check the parameters */assert_param(IS_PWR_REGULATOR(PWR_Regulator));assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));/* Select the regulator state in STOP mode ---------------------------------*/tmpreg = PWR->CR;/* Clear PDDS and LPDS bits */tmpreg &= CR_DS_MASK;/* Set LPDS bit according to PWR_Regulator value */tmpreg |= PWR_Regulator;/* Store the new value */PWR->CR = tmpreg;/* Set SLEEPDEEP bit of Cortex System Control Register */SCB->SCR |= SCB_SCR_SLEEPDEEP;/* Select STOP mode entry --------------------------------------------------*/if(PWR_STOPEntry == PWR_STOPEntry_WFI){   /* Request Wait For Interrupt */__WFI();}else{/* Request Wait For Event */__WFE();}/* Reset SLEEPDEEP bit of Cortex System Control Register */SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);  
}

待机模式标准库函数代码:

/*** @brief  Enters STANDBY mode.* @param  None* @retval None*/
void PWR_EnterSTANDBYMode(void)
{/* Clear Wake-up flag */PWR->CR |= PWR_CR_CWUF;/* Select STANDBY mode */PWR->CR |= PWR_CR_PDDS;/* Set SLEEPDEEP bit of Cortex System Control Register */SCB->SCR |= SCB_SCR_SLEEPDEEP;
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM   )__force_stores();
#endif/* Request Wait For Interrupt */__WFI();
}

5.2 进入低功耗模式参考代码

低功耗模式参考代码:

#include "delay.h"
#include "sys.h"
#include "usart.h"#define KEY0    GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)  //读取按键0         
#define KEY1    GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)  //读取按键1
#define KEY2    GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)  //读取按键2 
#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)  //读取按键3(WK_UP) uint8_t set_mcu_mode = 0;   //设置MCU模式,0:运行状态,1:睡眠模式,2:停机模式,3:待机模式//外部中断0服务程序
void EXTI0_IRQHandler(void)
{delay_ms(10);//消抖if(WK_UP == 1)	   //WK_UP按键{				 SystemInit();	 //MCU被唤醒,重新配置系统时钟set_mcu_mode = 0;printf("MCU wake up\r\n");}EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位  
}//外部中断2服务程序
void EXTI2_IRQHandler(void)
{delay_ms(10);//消抖if(KEY2 == 0)	  //按键KEY2{set_mcu_mode = 1; //需要进入睡眠模式printf("key2\r\n");}		 EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE2上的中断标志位  
}
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{delay_ms(10);//消抖if(KEY1 == 0)	 //按键KEY1{				 set_mcu_mode = 2; //需要进入停机模式printf("key1\r\n");}		 EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位  
}void EXTI4_IRQHandler(void)
{delay_ms(10);//消抖if(KEY0 == 0)	 //按键KEY0{set_mcu_mode = 3; //需要进入待机模式printf("key0\r\n");}		 EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志位  
}//外部中断初始化
void EXTIX_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE, ENABLE);//使能PORTA,PORTE时钟GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//KEY0-KEY2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,E3,E4GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;//WK_UP KEY-->GPIOA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉	  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟//GPIOE2 中断线以及中断初始化配置 下降沿触发GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);EXTI_InitStructure.EXTI_Line=EXTI_Line2; //KEY2EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOE3 中断线以及中断初始化配置 下降沿触发 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);EXTI_InitStructure.EXTI_Line=EXTI_Line3;  //KEY1EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOE4 中断线以及中断初始化配置 下降沿触发	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);EXTI_InitStructure.EXTI_Line=EXTI_Line4; //KEY0EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOA0 中断线以及中断初始化配置 上升沿触发 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_InitStructure.EXTI_Line=EXTI_Line0; //WK_UP KEYEXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;				//使能按键WK_UP所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;			//子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;				//使能按键KEY2所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;			//子优先级2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;				//使能按键KEY1所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;			//子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器  	  NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;				//使能按键KEY0所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;			//子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}void LED_Init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB5 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB5GPIO_SetBits(GPIOB,GPIO_Pin_5);						 	 //PB5 输出高
}int main(void)
{		delay_init();	    	//延时函数初始化	  uart_init(115200);	    //串口初始化为115200LED_Init();		  		//初始化与LED连接的硬件接口EXTIX_Init();		 	//外部中断初始化while(1){	    	if(set_mcu_mode > 0){switch (set_mcu_mode){case 1://进入睡眠模式printf("Enter sleep mode\r\n");__WFI();break;case 2://进入停机模式printf("Enter stop mode\r\n");PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);break;case 3://进入待机模式printf("Enter standby mode\r\n");PWR_EnterSTANDBYMode();break;default:break;}}GPIO_ResetBits(GPIOB, GPIO_Pin_5);	//点亮LED0delay_ms(200);	  GPIO_SetBits(GPIOB, GPIO_Pin_5);	//关闭LED0delay_ms(200);	}
}

示例代码测试结果:

1、MCU正常运行,LED0定时闪烁。
2、按下KEY0,MCU进入待机模式,LED0熄灭,再按下KEY3(WK_UP),MCU被唤醒继续运行。
3、按下KEY1,MCU进入停机模式,LED0熄灭,再按下KEY3(WK_UP),MCU被唤醒继续运行。
4、按下KEY2,MCU进入睡眠模式,LED0熄灭,再按下KEY3(WK_UP),MCU被唤醒继续运行。

结束语

上面的测试例子只是给大家做一个参考,实际上需要根据项目的具体需求去补充很多细节,比如进入低功耗模式的触发条件,唤醒的方式,以及进入睡眠之前对外设的处理,等等,这样才能保证在实现功能需求的同时,又能尽可能的把功耗降到最低。
好了,关于STM32如何进入低功耗模式就介绍到这里,如果你们有什么问题,欢迎评论区留言。

如果这篇文章能够帮到你,就…懂的。
请添加图片描述

相关文章:

  • HuggingFace-利用BERT预训练模型实现中文情感分类(下游任务)
  • 机器学习与计算机视觉 D2
  • 能否在一台电脑上安全地登录多个Facebook账号?
  • AI“胡说八道”?怎么解?
  • 前端JS模块化对外暴露的三种方法
  • Linux C 基于tcp和epoll在线聊天室
  • SpringCloud原理-OpenFeign篇(一、Hello OpenFeign项目示例)
  • PS 计数工具 基础使用方式讲解
  • 如何更有效地进行薪酬调查?
  • Virutalbox安装ubuntu22.04手把手教学
  • 大话java异常家族-检查与非检查
  • redis非关系型数据库(缓存型数据库)——中间件
  • 线性空间(也叫向量空间)、线性运算
  • 内存屏障与JVM指令
  • MongoDB的常用操作以及python连接MongoDB
  • 【347天】每日项目总结系列085(2018.01.18)
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • Git 使用集
  • HTTP请求重发
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • k8s 面向应用开发者的基础命令
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • Otto开发初探——微服务依赖管理新利器
  • PAT A1120
  • SpriteKit 技巧之添加背景图片
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 力扣(LeetCode)56
  • 浏览器缓存机制分析
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 我从编程教室毕业
  • 用element的upload组件实现多图片上传和压缩
  • puppet连载22:define用法
  • 昨天1024程序员节,我故意写了个死循环~
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)springboot教学评价 毕业设计 641310
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (一)80c52学习之旅-起始篇
  • (一)为什么要选择C++
  • (转)iOS字体
  • .NET MVC第三章、三种传值方式
  • .NetCore部署微服务(二)
  • .NET分布式缓存Memcached从入门到实战
  • /ThinkPHP/Library/Think/Storage/Driver/File.class.php  LINE: 48
  • @GlobalLock注解作用与原理解析
  • @html.ActionLink的几种参数格式