电源对电子设备的重要性不言而喻,它是保证系统稳定运行的基础,而保证系统能稳定运行后,又有低功耗的要求。
在很多应用场合中都对电子设备的功耗要求非常苛刻,如某些传感器信息采集设备,仅靠小型的电池提供电源,要求工作长达数年之久,且期间不需要任何维护;由于智慧穿戴设备的小型化要求,电池体积不能太大导致容量也比较小,所以也很有必要从控制功耗入手,提高设备的续行时间。
STM32有专门的电源管理外设监控电源并管理设备的运行模式,确保系统正常运行,并尽量降低器件的功耗。
- STM32电源管理系统
①备份域
STM32的备份域包括LSE振荡器、RTC(RTC是一个实时时钟,当主系统掉电后,内部RTC专门由一个外部备用电源给它供电,也就是说它有两个供电源,为RTC备份一个电源是确保整个STM32系统的时间是正常运行的)、备份寄存器及备份SRAM这些器件,这部分的电路可以通过STM32的VBAT引脚获取供电电源,在实际应用中一般会使用3V的钮扣电池对该引脚供电。
在图中备份域电路的左侧有一个电源开关结构,它的功能类似图中的双二极管,在它的上方连接了VBAT电源,下方连接了VDD主电源(一般为3.3V,纽扣电池电压为3V),右侧引出到备份域电路中。当VDD主电源存在时,由于VDD电压较高,备份域电路通过VDD供电,当VDD掉电时,备份域电路由钮扣电池通过VBAT供电,保证电路能持续运行,从而可利用它保留关键数据。
②调压器供电电路
在STM32的电源系统中调压器供电的电路是最主要、最核心的部分,调压器为备份域及待机电路以外的所有数字电路供电,其中包括内核、数字外设以及RAM,调压器的输出电压约为1.2V,因而使用调压器供电的这些电路区域被称为1.2V域。整个电路系统想要实现睡眠模式、待机模式等都离不开调压电路。
调压器可控制调节供电电路使系统运行在“运行模式”、“停止模式”以及“待机模式”下:
运行模式:调压器为 1.2 V 域(内核、存储器和数字外设)提供全功率。
停止模式:1.2V域运行在低功耗状态,1.2V区域的所有时钟都被关闭,相应的外设都停止了工作,但它会保留内核寄存器以及SRAM的内容;
待机模式:整个1.2V域都断电,该区域的内核寄存器及SRAM内容都会丢失(备份区域的寄存器及SRAM不受影响)。
为了提高转换精度,STM32的ADC配有独立的电源接口,方便进行单独的滤波。ADC的工作电源使用VDDA引脚输入,使用VSSA作为独立的地连接,VREF引脚则为ADC提供测量使用的参考电压。
- STM32低功耗模式
很多单片机都有低功耗模式,STM32F4 也不例外 ,运行状态下的 HCLK 为 CPU 提供时钟,内核执行程序代码。当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗,例如等待某个外部事件时。STM32F4 按功耗由高到低排列具有运行、睡眠、停止和待机四种工作模式。
上电复位后STM32处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式降低功耗,这三种模式中,电源消耗不同、唤醒时间不同、唤醒源不同,用户需要根据应用需求,选择最佳的低功耗模式。这三种低功耗模式层层递进,运行的时钟或芯片功能越来越少,因而功耗越来越低。
1.睡眠模式
在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,CM4核心的外设以及相关的外设时钟全都还照常运行。
有两种方式进入睡眠模式,它的进入方式决定了从睡眠唤醒的方式,分别是WFI(wait for interrupt,只要有中断就可以唤醒)和WFE(wait for event),即由等待“中断”唤醒和由“事件”唤醒。睡眠模式的各种特性见下表:
2.停止模式:
在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其1.2V区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以内核和外设的工作信息并不会丢失,记忆仍留存,唤醒后仍然可以从原状态继续执行。
所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断线(EXTI),唤醒,注意这里不是任意的中断。在停止模式中可以选择电压调节器为开模式或低功耗模式,可选择内部FLASH工作在正常模式或掉电模式。
需要注意的是,停止模式下,关闭了所有的外设,包括时钟系统也关闭了,被唤醒之后首先默认选择HSI内部时钟,如果停止模式之前工作时使用的是HSE外部时钟,整个系统还需要重新切换为HSE外部时钟。
3.待机模式
待机模式,它除了关闭所有的时钟,还把1.2V区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测boot条件,从头开始执行程序。它有四种唤醒方式,分别是WKUP(PA0)引脚的上升沿,RTC闹钟事件,NRST引脚的复位和IWDG(独立看门狗)复位。
- STM32实现睡眠模式
进入方式:内核寄存器的SLEEPDEEP = 0 ,然后调用WFI或WFE指令即可进入睡眠模式;另外若内核寄存器的SLEEPONEXIT=0时,进入“立即睡眠”模式,SLEEPONEXIT=1时,进入“退出时睡眠”模式。
实验内容:令指示灯处于工作状态表明系统正常运行,之后调用WFI指令使系统进入睡眠模式,同时指示灯熄灭。使用按键中断唤醒系统,同时唤醒时蜂鸣器工作表示系统已唤醒。
实验步骤:
1.配置RCC
2.配置GPIO管脚
3.配置中断优先级
4.编写代码
//main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
#include "gpio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("this is sleep mode testn");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET);
//指示灯亮表示系统正常运行
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); //指示灯灭表示系统进入睡眠模式
HAL_SuspendTick(); //关闭systick中断,否则系统会被此中断唤醒
//注意:关闭systick中断后,下面的代码不能使用HAL_Delay函数,此函数依赖systick中断
//调用封装好的函数,进入睡眠模式内部主要是调用__WFI()命令
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); //进入睡眠模式
//PWR_MAINREGULATOR_ON这个参数时保留的一个接口,用来调节调压器,但是睡眠状态下外设仍然工作
//因此此参数无效,PWR_SLEEPENTRY_WFI表示通过WFI指令进入睡眠
//进入睡眠模式,下面的代码不会执行
//唤醒后,才会依次执行下面的代码
printf("系统被唤醒!n");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //灯亮表示唤醒
}
}
//gpio.c
//进入中断处理函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
HAL_ResumeTick(); //回复systick中断,否则系统不能使用HAL_Delay
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET); //蜂鸣器响200ms表示系统被唤醒
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
}
}
内核停止运行时,无法向开发板烧录代码,此时向开发板烧录代码会提示内部错误。但是可以同时按下开发板复位键与烧录按钮并马上放开复位键(动作要迅速且流畅),就可以烧录代码。
- STM32实现停止模式
停止模式下,内核不会工作,外设也不会工作,但是外设当下的状态依旧保留,保留停止前的内核寄存器、内存的数据。因为只是停止了外设的时钟,而不会停止供电。外设不会进一步工作,功耗自然就下降。系统运行的参数仍然保留,I/O口的状态保留为停止前的状态。
进入方式:内核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=0,然后调用WFI或WFE指令即可进入停止模式;PWR_CR寄存器的LPDS=0时,调压器工作在正常模式,LPDS=1时工作在低功耗模式.
唤醒系统首先要恢复时钟,默认情况下一恢复首先选择HSI(内部时钟),如果进入停止模式前一些外设使用的时HSE(外部时钟)或者经过PLL倍频后更高速的时钟唤醒后就会导致由于时钟频率很低而无法正常工作。想要系统完全正常工作必须开启HSE以及PLL单元。
实验内容:令指示灯处于工作状态表明系统正常运行,之后调用WFI指令使系统进入睡眠模式,同时指示灯熄灭。使用按键中断唤醒系统,同时唤醒时蜂鸣器工作表示系统已唤醒。唤醒后系统默认选择HSI,重新使能HSE和PLL。
实验步骤:工程配置与睡眠模式下的配置相同.
编写代码:
//main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
#include "gpio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("this is sleep mode testn");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //指示灯亮表示系统正常运行
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); //指示灯灭表示系统进入停止模式
//HAL_SuspendTick();不需要关闭systick中断,因为要特定的中断线才能唤醒
//调用封装好的函数,进入睡眠模式内部主要是调用__WFI()命令
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); //进入停止模式
//PWR_MAINREGULATOR_ON表示调压器处于正常模式
//PWR_LOWPOWERREGULATOR_ON表示调压器处于低功耗模式(停止模式),
//PWR_SLEEPENTRY_WFI表示通过WFI指令进入睡眠
//进入停止模式,下面的代码不会执行
//唤醒后,才会依次执行下面的代码
printf("系统被唤醒!n");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //灯亮表示唤醒
}
}
//gpio.c
//编写时钟恢复函数
void CLK_Resume()
{
//使能HSE
__HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
//等待振荡器正常工作,振荡起来
{
//使能PLL
__HAL_RCC_PLL_ENABLE();
while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)//等待PLL正常工作
{
}
//选择PLL作为系统时钟
__HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK);
while(__HAL_RCC_GET_SYSCLK_SOURCE() != 0x08 )
{
}
}
//进入中断处理函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
CLK_Resume(); //恢复时钟,打开HSE和PLL
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET);
//蜂鸣器响200ms表示系统被唤醒
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
}
}
- STM32实现待机模式
待机模式不仅关闭内核与外设的时钟,而且也切断了电源,这样系统完全不能工作,状态得不到不存,寄存器与内存信息丢失。相当于复位,唤醒后从头开始运行。除复位引脚、RTC_AF1引脚及WKUP引脚,其它I/O口均工作在高阻态。
进入方式:内核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=1,PWR_CR寄存器中的唤醒状态位WUF=0,然后调用WFI或WFE指令即可进入待机模式,唤醒后唤醒状态位WUF=1。
待机模式的唤醒方式只能通过一些固定的方式,如:通过WKUP引脚的上升沿,RTC闹钟、唤醒、入侵、时间戳事件或NRST引脚外部复位及IWDG复位唤醒。
实验内容:令指示灯处于工作状态表明系统正常运行,之后调用WFI指令使系统进入睡眠模式,同时指示灯熄灭。使用按键唤醒系统,同时唤醒时蜂鸣器工作表示系统已唤醒。事实上,上述睡眠模式与停止模式的工程配置中,按键对应的PA0就是一个WKUP引脚,因此这里仍然使用按键唤醒。
实验步骤:工程配置与睡眠模式下的配置相同
编写代码:
//main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
#include "gpio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("this is stand mode testn");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //指示灯亮表示系统正常运行
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); //指示灯灭表示系统进入停止模式
//HAL_SuspendTick();不需要关闭systick中断,因为要特定的中断线才能唤醒
//进入待机模式前,必须使能唤醒管脚,且唤醒状态位WUF应当清0
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); //使能唤醒引脚,f407只有一个唤醒管脚PA0
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);//清除WUF位为0,为1时表示被唤醒
HAL_PWR_EnterSTANDBYMode(); //进入待机模式
//进入待机模式,下面的代码不会执行
//唤醒后,下面的代码也不会执行
printf("系统被唤醒!n");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //灯亮表示唤醒
}
}
//系统进入待机模式后,按下按键唤醒,并不会进入中断,
//而是从头开始进行工作,是一个复位操作
//原来的状态得不到保存,因此进入待机模式HAL_PWR_EnterSTANDBYMode()
//下面的代码永远不会被执行到
评论
查看更多