历史上的今天
今天是:2025年08月20日(星期三)
2019年08月20日 | stm32之电源管理(实现低功耗)
2019-08-20 来源:eefocus
前言:STM32F10xxx系列产品都有电源管理模块,芯片功耗会影响到一个产品的续航能力;比如在一些终端传感器场合里,为了减轻后期的维护投入,要求长期工作时间较长,更需要合理的芯片功耗管理。芯片自带几种运行模式,包括正常模式、睡眠模式、停止模式、待机模式。越往后,芯片的功耗越低,但能执行功能就越少。低功耗的电源管理策略就是在芯片不需要对外界响应的时候进入低功耗模式,而当外界条件满足的时候,退出低功耗模式(唤醒),正常执行处理工作。下面对其模式之间的转换和各个模式下的芯片内部的运转情况等一探究竟。
写代码前要先了解芯片的特性及工作原理,难免会先阅读一些长长的文档。下面核心讲解一些要点。
1.硬件原理
下图是芯片的电源框架:

图左边7个电压点对应芯片的7个引脚,在芯片电路原理图能找到对应的引脚。
、:是ADC转换器的参考电压,有些芯片没有这连个引脚,内部已经把他们接到、了。
、:是ADC转换器的供电电源,独立电源供电是为了过滤和屏蔽来自印刷电路板上的毛刺干扰,提高转换的精确度。(也可以直接连到、)。
、:STM32的工作电压(VDD)为2.0~3.6V。通过内置的电压调节器提供所需的1.8V电源。
:使用电池或其他电源连接到VBAT脚上,当VDD断电时,可以保存备份寄存器的内容和维持RTC的
功能。(如果没有外部电池,好像不接也可以,但是数据手册说必须接到)。
电池备份区域:
当备份区域由VDD(内部模拟开关连到VDD)供电时,下述功能可用:
● PC14和PC15可以用于GPIO或LSE(低速外部时钟)引脚
● PC13可以作为通用I/O口、TAMPER引脚、RTC校准时钟、RTC闹钟或秒输出
当后备区域由VBAT供电时(VDD消失后模拟开关连到VBAT),可以使用下述功能:
● PC14和PC15只能用于LSE(低速外部时钟)引脚
● PC13可以作为TAMPER引脚、RTC闹钟或秒输出
电压调节器:
复位后调节器总是使能的。根据应用方式它以3种不同的模式工作。
● 运转模式:调节器以正常功耗模式提供1.8V电源(内核,内存和外设)。
● 停止模式:调节器以低功耗模式提供1.8V电源,以保存寄存器和SRAM的内容。
● 待机模式:调节器停止供电。除了备用电路和备份域外,寄存器和SRAM的内容全部丢失。
2.低功耗模式
STM32F10xxx有三种低功耗模式:
● 睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行)
● 停止模式(所有的时钟都已停止)
● 待机模式(1.8V电源关闭)
此外,在运行模式下,可以通过以下方式中的一种降低功耗:
● 降低系统时钟
● 关闭APB和AHB总线上未被使用的外设时钟。

注意:在睡眠模式、停止模式及待机模式中,若备份区域电源正常供电,备份区域的RTC都可以正常运行、备份区域内的寄存器及备份区域内的SRAM数据会被保存,不受功耗模式影响。
3.睡眠模式实验
下面代码利用编译器内置函数__WFI()进入睡眠,任何中断将退出睡眠(实验使用串口中断和外部中断)。利用串口将芯片状态信息发送出来。可以先把代码复制到工程编译下载,实验现象通过串口上位机观察,如果有可调电源的话,可以对比正常工作和睡眠模式下的电流大小,正常来说睡眠模式下功率低,那么电流会比正常工作下低。下面程序并不复杂,程序进入while循环延时一段时间就会进入睡眠状态,利用上位机向串口发送数据或者将PA.0引脚接电源都可产生中断,从而退出睡眠模式。
#include "stm32f10x.h"
#include "stdio.h"
static void EXTI_Key_Config(void);
static void NVIC_Configuration(void);
static void USART1_Config(void);
static void Delay(__IO u32 nCount);
int main(void)
{
USART1_Config();
EXTI_Key_Config();
//配置中断控制器NVIC
NVIC_Configuration();
while(1)
{
printf("STM32正常运行.rn");
Delay(0xfffff);
//NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,DISABLE);//调用__WFI时立即进入睡眠
NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,ENABLE);//调用__WFI时,等待系统从最低优先级的中断处理程序中退出后进入睡眠
printf("STM32进入睡眠.rn");
__WFI();//WFI指令进入睡眠
//开始等待中断唤醒
Delay(0xfffff);
printf("已退出睡眠模式.rn");
}
}
static void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
//开启外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
//初始化 GPIOA.0 设置为下拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//GPIOA.0 中断线配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
//GPIOA.0 中断初始化配置
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿时进入中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
//初始化外设EXTI寄存器
EXTI_Init(&EXTI_InitStructure);
}
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//配置串口1(USART1)时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
//配置串口1(USART1 Tx (PA.09))
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置串口1 USART1 Rx (PA.10)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//串口1模式(USART1 mode)配置
USART_InitStructure.USART_BaudRate = 9600;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口
}
int fputc(int ch, FILE *f)//重写标准库的fputc函数
{
//将Printf内容发往串口
USART_SendData(USART1, (unsigned char) ch);
while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
return (ch);
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);//使能外部中断 PA.0
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_Init(&NVIC_InitStructure);//使能串口1中断
}
void Delay(__IO u32 nCount) //简单的延时函数
{
for(; nCount != 0; nCount--);
}
在stm32f10x_it.c文件加入:
#include "delay.h"
void EXTI0_IRQHandler(void)
{
Delay(0xFFFFF);//防抖
//检查指定的EXTI0线路触发请求发生与否
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
printf("按键中断唤醒.rn");
}
//清除EXTI0线路挂起位
EXTI_ClearITPendingBit(EXTI_Line0);
}
void USART1_IRQHandler(void)
{
unsigned char code;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
code=USART_ReceiveData(USART1);
printf("串口中断唤醒.rn");
}
}
睡眠模式的各种特性

注意:在系统处于睡眠低功耗模式(包括后面介绍的停止模式、待机模式)时,不能用下载器进行程序下载,所以下载程序时要先把系统唤醒。或者使用如下方法:按着板子的复位键,点击电脑端的“下载”,然后松开复位键,就能正常给板子下载程序了。
4.停止模式实验
停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,PLL、HSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
停止模式的功耗比睡眠模式更低,代码操作上相对比睡眠模式复杂一点。跟睡眠模式的唤醒不同,只有EXTI线的中断才能退出停止模式,因为其他外设在停止模式时被关闭,并不能响应中断。将mani函数替换为下面代码,其他不变:
int main(void)
{
USART1_Config();
EXTI_Key_Config();
NVIC_Configuration();//配置中断控制器NVIC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能电源管理单元的时钟
while(1)
{
printf("STM32正常运行.rn");
Delay(0xfffff);
printf("STM32进入停止模式.rn");
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);//进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒
//PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);//进入停止模式,设置电压调节器为正常模式,等待中断唤醒
//开始等待任意EXTI线中断唤醒
SystemInit();//唤醒后需要恢复系统时钟,因为退出停止模式后,系统默认使用的HSI作为系统时钟
/*实际上在运行main函数前,会先执行SystemInit函数以配置系统时钟,这个在启动文件里可以看到。*/
//刚退出停止模式时,使用HSI作为系统时钟,回影响串口波特率
//输出不对,在重新配置时钟后才能使用串口的输出
Delay(0xfffff);
printf("已退出停止模式.rn");
}
}
停止模式的各种特性

5.待机模式实验
待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。也就是说从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测boot条件,从头开始执行程序。它有4种唤醒方式,分别是WAUP(PA0)引脚的上升沿、RTC闹钟事件、NRST引脚的复位和IWDG(独立看门狗)复位。
我们不需要对PA.0引脚进行如上面的初始化,也不需要初始化一个外部中断,将下面两个函数替换,其余保持不变:
int main(void)
{
USART1_Config();
//EXTI_Key_Config();
//配置中断控制器NVIC
NVIC_Configuration();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能电源管理单元的时钟
if(PWR_GetFlagStatus(PWR_FLAG_WU)){
printf("rn待机模式复位.rn");
}else{
printf("rn非待机模式复位.rn");
}
while(1)
{
printf("STM32正常运行.rn");
Delay(0xfffff);
printf("STM32进入待机模式.rn");
PWR_ClearFlag(PWR_FLAG_WU);//清除唤醒标志状态
PWR_WakeUpPinCmd(ENABLE);//使能Wake引脚的唤醒功能,使能PA0
PWR_EnterSTANDBYMode();//进入待机模式
}
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//NVIC_Init(&NVIC_InitStructure);//使能外部中断 PA.0
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_Init(&NVIC_InitStructure);//使能串口1中断
}
程序下载后,按下复位键,串口会打印非待机模式复位,接着运行while函数,延时后进入待机模式,等待唤醒,在PA0引脚给上升沿信号,串口打印已待机模式复位,代码重头开始执行。
待机模式的各种特性

最后,除了利用上面三种模式实现低功耗外,还可以在运行模式下,关闭某些外设时钟或者利用分频器降低外设时钟,同样也可以减低系统功耗。电池备份区域部分这里没有细说,后面单独一篇介绍。
史海拾趣
|
CPU是STM32F103CB,无操作系统。 通过UART1接受GPRS发来的数据,在中断函数中 USART1_IRQHandler 中进行处理 unsigned char a_GPRSData[500]; unsigned int g_DataLength; void USART1_IRQHandler(void) ...… 查看全部问答> |
|
是一个U盘感染的病毒,在D盘中出现一个autorun.inf文件,同时点D盘右健会多一个\"浏览\"项,而这个文件的内容是: [autorun] open=.\\recycled\\info.exe shell\\1=浏览 shell\\1\\Command=.\\recycled\\info.exe shellexecute=.\\recycled\\info. ...… 查看全部问答> |
|
#include sbit ds=P3^7; //0-F数码管显示(共阴) unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //0-9数码管的显示,共阴带小数点 unsigned char code tabledot[]={ ...… 查看全部问答> |
|
使用的是ep2s180f1020i4的片子,配置芯片epcs64,用flash programmer 进行烧写,从状态栏来看 烧写成功了,但是上电后没有任何反应,不止nios没跑起来,连逻辑都没烧进去,但是在线运行时是正常的,单独烧写逻辑从新上电也是可以起来的,就是用nios ...… 查看全部问答> |
|
经过再三调试,我人生的第一版开关电源诞生了,激动ing,不过也仍有很多问题没有解决!希望高手指教!这里好像不能传附件啊,详细过程在下面链接里面了,有兴趣的亲可以看看,多多指教!… 查看全部问答> |




