赞
踩
很多单片机都有低功耗模式,STM32 也不例外。当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗。
这部分不是我负责,但是也是有必要看一下的。
参看:
STM32F1开发指南-库函数版本_V3.2.pdf
STM32中文参考手册_V10.pdf
在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
STM32有三种低功耗模式:
● 睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行)
● 停止模式(所有的时钟都已停止)
● 待机模式(1.8V电源关闭)
此外,在运行模式下,可以通过以下方式中的一种降低功耗:
● 降低系统时钟
在运行模式下,通过对预分频寄存器进行编程,可以降低任意一个系统时钟(SYSCLK、
HCLK、 PCLK1、 PCLK2)的速度。进入睡眠模式前,也可以利用预分频器来降低外设的时钟。
● 关闭APB和AHB总线上未被使用的外设时钟。
在运行模式下,任何时候都可以通过停止为外设和内存提供时钟(HCLK和PCLKx)来减少功耗。为了在睡眠模式下更多地减少功耗,可在执行WFI或WFE指令前关闭所有外设的时钟。通 过 设 置 AHB 外 设 时 钟 使 能 寄 存 器 (RCC_AHBENR) 、 APB2 外 设 时 钟 使 能 寄 存 器(RCC_APB2ENR)和APB1外设时钟使能寄存器(RCC_APB1ENR)来开关各个外设模块的时钟。
到此了解到了STM32的三种低功耗模式,和在运行模式下如何降低功耗的方式。
接下来分别看一下这三种低功耗模式。
通过执行WFI或WFE指令进入睡眠状态。根据Cortex™-M3系统控制寄存器中的SLEEPONEXIT位的值,有两种选项可用于选择睡眠模式进入机制:
● SLEEP-NOW:如果SLEEPONEXIT位被清除,当WRI或WFE被执行时,微控制器立即进入睡眠模式。
● SLEEP-ON-EXIT:如果SLEEPONEXIT位被置位,系统从最低优先级的中断处理程序中退出时,微控制器就立即进入睡眠模式。
在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
如果执行WFI指令进入睡眠模式,任意一个被嵌套向量中断控制器响应的外设中断都能将系统从睡眠模式唤醒。
如果执行WFE指令进入睡眠模式,则一旦发生唤醒事件时,微处理器都将从睡眠模式退出。
唤醒事件可以通过下述方式产生:
● 在外设控制寄存器中使能一个中断,而不是在NVIC(嵌套向量中断控制器)中使能,并且在Cortex-M3系统控制寄存器中使能SEVONPEND位。当MCU从WFE中唤醒后,外设的中断挂起位和外设的NVIC中断通道挂起位(在NVIC中断清除挂起寄存器中)必须被清除。
● 配置一个外部或内部的EXIT线为事件模式。 当MCU从WFE中唤醒后,因为与事件线对应的挂起位未被设置,不必清除外设的中断挂起位或外设的NVIC中断通道挂起位。
该模式唤醒所需的时间最短,因为没有时间损失在中断的进入或退出上。
停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和HSE RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。
在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
在停止模式下,通过设置电源控制寄存器(PWR_CR)的LPDS位使内部调节器进入低功耗模式,能够降低更多的功耗。
如果正在进行闪存编程,直到对内存访问完成,系统才进入停止模式。
如果正在进行对APB的访问,直到对APB访问完成,系统才进入停止模式。
可以通过对独立的控制位进行编程,可选择以下功能:
● 独立看门狗(IWDG):可通过写入看门狗的键寄存器或硬件选择来启动IWDG。一旦启动了独立看门狗,除了系统复位,它不能再被停止。
● 实时时钟(RTC):通过备份域控制寄存器 (RCC_BDCR)的RTCEN位来设置。
● 内部RC振荡器(LSI RC):通过控制/状态寄存器 (RCC_CSR)的LSION位来设置。
● 外部32.768kHz振荡器(LSE):通过备份域控制寄存器 (RCC_BDCR)的LSEON位设置。
在停止模式下,如果在进入该模式前ADC和DAC没有被关闭,那么这些外设仍然消耗电流。通过设置寄存器ADC_CR2的ADON位和寄存器DAC_CR的ENx位为0可关闭这2个外设。
当一个中断或唤醒事件导致退出停止模式时, HSI RC振荡器被选为系统时钟。
当电压调节器处于低功耗模式下,当系统从停止模式退出时,将会有一段额外的启动延时。如果在停止模式期间保持内部调节器开启,则退出启动时间会缩短,但相应的功耗会增加。
待机模式可实现系统的最低功耗。 该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。 PLL、 HSI和HSE振荡器也被断电。 SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。
可以通过设置独立的控制位,选择以下待机模式的功能:
● 独立看门狗(IWDG):可通过写入看门狗的键寄存器或硬件选择来启动IWDG。一旦启动了独立看门狗,除了系统复位,它不能再被停止。
● 实时时钟(RTC):通过备用区域控制寄存器(RCC_BDCR)的RTCEN位来设置。
● 内部RC振荡器(LSI RC):通过控制/状态寄存器(RCC_CSR)的LSION位来设置。
● 外部32.768kHz振荡器(LSE):通过备用区域控制寄存器(RCC_BDCR)的LSEON位设置。
当一个外部复位(NRST引脚)、 IWDG复位、 WKUP引脚上的上升沿或RTC闹钟事件的上升沿发生时,微控制器从待机模式退出。从待机唤醒后,除了电源控制/状态寄存器,所有寄存器被复位。
从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚、读取复位向量等)。 电源控制/状态寄存器将会指示内核由待机状态退出。
在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
● 复位引脚(始终有效)
● 当被设置为防侵入或校准输出时的TAMPER引脚
● 被使能的唤醒引脚
默认情况下,如果在进行调试微处理器时,使微处理器进入停止或待机模式,将失去调试连接。这是因为Cortex™-M3的内核失去了时钟。
然而,通过设置DBGMCU_CR寄存器中的某些配置位,可以在使用低功耗模式下调试软件。
相关库函数参看文件:stm32f10x_pwr.c / stm32f10x_pwr.h
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
void PWR_EnterSTANDBYMode(void);
作用:前者进入停机状态,后者进入待机状态。
void PWR_WakeUpPinCmd(FunctionalState NewState);
void PWR_BackupAccessCmd(FunctionalState NewState);
作用:前者使能WK_UP引脚唤醒(正常模式下,WK_UP引脚作为普通IO口,待机模式下设置成唤醒功能),后者使能BKP后备区域访问使能。
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
void PWR_ClearFlag(uint32_t PWR_FLAG);
作用:前者获取电源控制的状态位,后者清除相应的状态位。
文件: core_cm3.h
__WFI();
__WFE();
作用:CM3内核的WFI(等待中断)、WFE(等待事件)指令。
================================================
好了,到此基本上三个低功耗模式相关知识都讲完了。
接下来网上更多的是再介绍一下待机模式的软件实现就结束了。
既然标题是详解,就要讲一下其他两个呢。
哈哈,不做标题党!!
● 配置中断
PC13/TAMPER 连接 KEY2按键
配置 PC13 为线中断口,并设置中断优先级
配置嵌套向量中断控制器NVIC PA13
中断配置之前有讲过的这里不再重复,参看:STM32开发 – 外部中断详解
__WFI(); //进入睡眠模式,等待中断唤醒 方式一
或
__WFE(); //方式二
●等待运行至进入睡眠模式之后,按下KEY2键,退出睡眠模式,程序得以继续运行。
睡眠模式其实很简单了,就是通过WFI/WFE进入睡眠,通过任一中断唤醒。
● 配置中断
PC13/TAMPER 连接 KEY2按键
配置 PC13 为线中断口,并设置中断优先级
配置嵌套向量中断控制器NVIC PA13
配置SysTick 为10us中断一次
●使能电源管理单元的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
●进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
按下KEY2键,退出停止模式,程序得以继续运行。
●中断函数
void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line13) != RESET) //确保是否产生了EXTI Line中断 { /* 刚从停机唤醒,由于时钟未配置正确, 此printf语句的内容不能正常发送出去 */
printf("\r\n 进入中断 \r\n"); SYSCLKConfig_STOP(); //停机唤醒后需要启动HSE LED1( ON ); LED2( ON ); LED3( ON ); //点亮所有LED一段时间指示停机唤醒 Delay(0xFFFFFF); LED1( OFF ); LED2( OFF ); LED3( OFF ); /*由于前面已经重新启动了HSE, 所以本printf语句能正常发出 */ printf("\r\n 退出中断 \r\n"); EXTI_ClearITPendingBit(EXTI_Line13); //清除中断标志位 }
}
●停机唤醒后配置系统时钟: 使能 HSE, PLL并且选择PLL作为系统时钟.
void SYSCLKConfig_STOP(void)
{
ErrorStatus HSEStartUpStatus;
/* 使能 HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* 等待 HSE 准备就绪 */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* 使能 PLL */
RCC_PLLCmd(ENABLE);
/* 等待 PLL 准备就绪 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* 选择PLL作为系统时钟源 */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* 等待PLL被选择为系统时钟源 */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
}
● 进入停机模式:
PWR_EnterSTOPMode 进入停机模式
/** * @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);
}
看一下上面这个函数是不是就是以下这些功能呢?
(进入停机模式)
在以下条件下执行WFI(等待中断)或WFE(等待事件)指令:
– 设置Cortex-M3系统控制寄存器中的SLEEPDEEP位
– 清除电源控制寄存器(PWR_CR)中的PDDS位
– 通过设置PWR_CR中LPDS位选择电压调节器的模式
注:为了进入停止模式,所有的外部中断的请求位(挂起寄存器(EXTI_PR))和RTC的闹钟标志都必须被清除,否则停止模式的进入流程将会被跳过,程序继续运行。
● 退出停机模式:
设置任一外部中断线为中断模式,触发中断退出停机模式。
最后要注意唤醒后需要配置系统时钟: 使能 HSE, PLL并且选择PLL作为系统时钟.
或者在中断处理函数中,进行下系统初始化就可以了。
中断执行:
SystemInit();
● 使能电源管理单元的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);
● 使能电源管理单元的时钟
if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)
{
printf("\r\n 使能后检测,待机唤醒复位 \r\n");
}
else
printf("\r\n 使能后检测,上电复位 \r\n");
● 配置中断
PC13/TAMPER 连接 KEY2按键
PA0/WKUP 连接 WKUP按钮 – KEY1按键
配置 PC13 为线中断口,并设置中断优先级
配置嵌套向量中断控制器NVIC PA13
● 上电LED灯闪烁
●长按下KEY2键(持续超过3s),进入待机模式
按键检查:
/** * @brief 用于检测按键是否被长时间按下 * @param 无 * @retval 1 :按键被长时间按下 0 :按键没有被长时间按下 */ uint8_t PWR_Check_Standby(void) { uint8_t downCnt =0;//记录按下的次数 uint8_t upCnt =0;//记录松开的次数
while(1)//死循环,由return结束 { Delay(0xFFFF);//延迟一段时间再检测 if(GPIO_ReadInputDataBit (GPIOC,GPIO_Pin_13) == RESET)//检测到按下按键 { LED1(ON);LED2(ON);LED3(ON);//点亮所有LED灯 downCnt++; //记录按下次数 upCnt=0; //清除按键释放记录 if(downCnt>=100)//按下时间足够 { LED1(OFF);LED2(OFF);LED3(OFF); return 1; //检测到按键被时间长按下 } } else { upCnt++; //记录释放次数 if(upCnt>5) //连续检测到释放超过5次 { LED1(OFF);LED2(OFF);LED3(OFF); //关闭所有LED灯 return 0; //按下时间太短,不是按键长按操作 } }// if(GPIO_ReadInputDataBit }//while
}
中断函数:
void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line13) != RESET) //确保是否产生了EXTI Line中断 {
printf("\r\n 进入EXTI13中断 \r\n"); if(PWR_Check_Standby()) { /* 使能WKUP引脚的唤醒功能 */ PWR_WakeUpPinCmd (ENABLE); /* 进入待机模式 */ PWR_EnterSTANDBYMode(); } EXTI_ClearITPendingBit(EXTI_Line13); //清除中断标志位 }
}
●再按下KEY1键(WKUP按钮 )退出待机模式,程序得以继续运行。
这个KEY1键和KEY2键连接哪个引脚,必须搞清楚哦。
PC13/TAMPER 连接 KEY2按键
PA0/WKUP 连接 WKUP按钮 -- KEY1按键
一开始没有注意KEY1键连接的WKUP引脚,怎么都没能理解为啥按一下键也没有触发中断就唤醒了呢?。。。
● 进入待机模式:
PWR_EnterSTANDBYMode 进入待机模式
/**
* @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();
}
看一下上面这个函数是不是就是以下这些功能呢?
(进入待机模式)
在以下条件下执行WFI(等待中断)或WFE(等待事件)指令:
– 设置Cortex™-M3系统控制寄存器中的SLEEPDEEP位
– 设置电源控制寄存器(PWR_CR)中的PDDS位
– 清除电源控制/状态寄存器(PWR_CSR)中的WUF位
● 退出待机模式:
首先需要使能WKUP引脚的唤醒功能
PWR_WakeUpPinCmd 使能唤醒
/**
* @brief Enables or disables the WakeUp Pin functionality.
* @param NewState: new state of the WakeUp Pin functionality.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void PWR_WakeUpPinCmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));
*(__IO uint32_t *) CSR_EWUP_BB = (uint32_t)NewState;
}
待机模式下,按下WKUP按钮 – KEY1按键,WKUP引脚的上升沿。
则退出待机模式,程序得以继续运行。
当然还有其他几种退出待机模式的方法:
RTC闹钟事件的上升沿、 NRST引脚上外部复位、 IWDG复位
稍后会接着讲。
这篇文章简单讲解了一下这三种低功耗模式。
而且还是没有讲全。。。
接下来就该思考一下了,上图里低功耗模式介绍里的内核、外设、系统时钟、1.8v内核电源 等等都是啥意思??这三种低功耗模式该如何选择呢?
GPS/4G模块/蓝牙进入休眠和其他功能电路供电切断 这些又该如何操作?
再有stm32f4里低功耗模式与之又有什么不同呢?
然后,别光顾着看代码,具体硬件怎么测低功耗呢?
还有以上讲的都是标准库,那么具体到HAL库低功耗又该如何操作?
且听下回分解!!!
如需转载请注明出处:https://juyou.blog.csdn.net/article/details/95364296
</div> <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-b6c3c6d139.css" rel="stylesheet"> <div class="more-toolbox"> <div class="left-toolbox"> <ul class="toolbox-list"> <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#csdnc-thumbsup"></use> </svg><span class="name">点赞</span> <span class="count">3</span> </a></li> <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-Collection-G"></use> </svg><span class="name">收藏</span></a></li> <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-fenxiang"></use> </svg>分享</a></li> <!--打赏开始--> <!--打赏结束--> <li class="tool-item tool-more"> <a> <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg> </a> <ul class="more-box"> <li class="item"><a class="article-report">文章举报</a></li> </ul> </li> </ul> </div> </div> <div class="person-messagebox"> <div class="left-message"><a href="https://blog.csdn.net/qq_29350001"> <img src="https://profile.csdnimg.cn/A/B/7/3_qq_29350001" class="avatar_pic" username="qq_29350001"> <img src="https://g.csdnimg.cn/static/user-reg-year/2x/4.png" class="user-years"> </a></div> <div class="middle-message"> <div class="title"><span class="tit"><a href="https://blog.csdn.net/qq_29350001" data-report-click="{"mod":"popu_379"}" target="_blank">聚优致成</a></span> <span class="flag expert"> <a href="https://blog.csdn.net/home/help.html#classicfication" target="_blank"> <svg class="icon" aria-hidden="true"> <use xlink:href="#csdnc-blogexpert"></use> </svg> 博客专家 </a> </span> </div> <div class="text"><span>发布了372 篇原创文章</span> · <span>获赞 1898</span> · <span>访问量 250万+</span></div> </div> <div class="right-message"> <a href="https://bbs.csdn.net/forums/p-qq_29350001" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-messageboard">他的留言板 </a> <a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a> </div> </div> </div>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。