stm32 低功耗设计[操作寄存器+库函数]
- 睡眠模式(内核停止,外设运行)
- 停机模式(所有时钟都停止)
待机模式(1.8V内核电源也关闭)
在这三种模式中,最低功耗的是待机模式,在此模式下,最低只需要2uA左右的电流。整个1.8V供电区被断电,PLL、HSI、HSE振荡器都被关闭。SRAM和寄存器内容丢失。停机模式是次低功耗的的,其典型的电流损耗在20uA左右。最后就是睡眠模式。stm32低功耗一览表这三种低功耗模式,唤醒后程序都会初始化运行。在例子中做了一番论证,结果如此。直接操作寄存器进入待机模式的通用步骤,其中涉及到2个寄存器,也就是电源控制寄存器(PWR_CR)和电源控制/状态寄存器(PWR_CSR)。电源控制寄存器(PWR_CR),该寄存器的各位描述如下:这是一个低9位有效的寄存器。DBP[8]:取消后备区域的写保护 位 8 在复位后,RTC和后备寄存器处于被保护状态以防意外写入。0:禁止写入RTC和后备寄存器 1:允许写入RTC和后备寄存器
PLS[ 7:5 ]:PVD电平选择。 这些位用于选择电源电压监测器的电压阀值。
000:2.2V 100:2.6V 001:2.3V 101:2.7V010:2.4V 110:2.8V 011:2.5V 111:2.9VPVDE[4]:电源电压监测器(PVD)使能。 0:禁止PVD 1:开启PVD
- CSBF[3]:清除待机位,始终读出为0。 0:无功效 1:清除SBF待机位(写)
- CWUF[2]:清除唤醒位,始终读出为0。 0:无功效 1:2个系统时钟周期后清除WUF唤醒位(写)
- PDDS[1]:掉电深睡眠,与LPDS位协同操作。 0:当CPU进入深睡眠时进入停机模式,调压器的状态由LPDS位控制。 1:CPU进入深睡眠时进入待机模式。
- LPDS[0]:深睡眠下的低功耗。PDDS=0时,与PDDS位协同操作 0:在停机模式下电压调压器开启 1:在停机模式下电压调压器处于低功耗模式
- EWUP[8]:使能WKUP引脚 ,在系统复位时清除这一位。
- PVDO[2]:PVD输出 ,当PVD被PVDE位使能后该位才有效。
- SBF[1]:待机标志。
- WUF[0]:唤醒标志。 待机函数实现:(参见 system.c文件)
//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI
__asm void WFI_SET(void)
{
WFI;
}
//进入待机模式
//参数说明:
// var = 0 ,设定为睡眠模式
// var = 1 ,设定为停机模式,电流消耗在20uA左右
// var = 2 ,设定为待机模式,电流消耗在2uA左右
void Sys_Standby(u8 var)
{
RCC->APB1ENR |= 1<<28; //使能电源时钟
switch(var)
{
case 0:{ break; } //WFI进入睡眠模式
case 1:{ //PDDS+LPDS+SLEEPDEEP+WFI进入停机模式
SCB->SCR |= 1<<2; //使能SLEEPDEEP位 (SYS->CTRL)
PWR->CR |= 1<<0; //LPDS置位
PWR->CR |= 1<<1; //PDDS置位
break;
}
case 2:{ //PDDS+SLEEPDEEP+WFI进入待机模式
SCB->SCR |= 1<<2; //使能SLEEPDEEP位 (SYS->CTRL)
PWR->CR|=1<<1; //PDDS置位
break;
}
}
PWR->CR |= 1<<2; //清除Wake-up 标志
PWR->CSR |= 1<<8; //允许写入RTC和BKP寄存器
WFI_SET(); //执行WFI指令
}
//系统软复位
void Sys_Soft_Reset(void)
{
SCB->AIRCR =0X05FA0000|(u32)0x04;
}
#include <stm32f10x_lib.h>
#include “system.h”
#include “wdg.h”
#include “exti.h”
#define LED1 PAout(4)
#define LED2 PAout(5)
#define PWR_MODE_Sleep 0 //开启睡眠模式
#define PWR_MODE_STOP 1 //开启停机模式
#define PWR_MODE_STANDBY 0 //开启待机模式
void Gpio_Init(void);
int main(void)
{
u32 i= 10,j=10;
Rcc_Init(9); //系统时钟设置
Exti_Init(GPIO_A,0,FTIR); //设置PA1为下降沿触发,参数GPIO_x 和 FTIR 在system.h中有定义
Nvic_Init(0,0,EXTI0_IRQChannel,0); //设置外部中断
Gpio_Init();
while(i--){
LED1 = !LED1;
delay(30000); //延时30ms
}
#if PWR_MODE_Sleep //睡眠模式,外部中断唤醒后会复位
Sys_Standby(0);
#elif PWR_MODE_STOP //停机模式,外部中断唤醒,唤醒后复位
Sys_Standby(1);
#elif PWR_MODE_STANDBY //待机模式,由独立看门狗唤醒,唤醒后会初始化,LED闪烁5次后,暗一段时间
Iwdg_Init(3,2000); //设置为1.6s内不喂狗复位,使用独立看门狗唤醒,唤醒后复位
Sys_Standby(2);
#endif
while(j--){ //这段程序用于检验唤醒后是否会继续运行后面的程序,还是会导致复位
LED2 = !LED2;
delay(10000); //延时10ms
}
}
void Gpio_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
GPIOA->CRL|=0x33334444;
}
#include “stm32f10x_it.h”
#include “system.h”
#define LED1 PAout(4)
#define LED2 PAout(5)
#define LED3 PAout(6)
#define LED4 PAout(7)
void EXTI0_IRQHandler(void)
{
LED4 = !LED4;
EXTI->PR = 1<<0; //清除中断标志位
}
待机相关代码参见 system.c文件中
#include “stm32f10x.h”
#include “stdio.h”
#define PRINTF_ON 1
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void EXTI_Configuration(void);
void IWDG_Configuration(void);
#define PWR_MODE_Sleep 0 //开启睡眠模式
#define PWR_MODE_DeepSleep 1 //开启停机模式
#define PWR_MODE_STANDBY 0 //开启待机模式
vu32 DelayTime = 10000000;
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
EXTI_Configuration();
SysTick_Config(10000000);
while(--DelayTime);
#if PWR_MODE_Sleep //睡眠模式
PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI); //唤醒后时钟变为内置8MHz
#elif PWR_MODE_DeepSleep //停机模式
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI); //唤醒后时钟变为内置8MHz
#elif PWR_MODE_STANDBY //待机模式
IWDG_Configuration(); //设置为2s内不喂狗复位,使用独立看门狗唤醒
PWR_EnterSTANDBYMode(); //唤醒后会初始化程序
#endif
while(1);
}
void IWDG_Configuration(void)
{
RCC_LSICmd(ENABLE); //打开LSI
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET);
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_32);
IWDG_SetReload(2000); //max 0xFFF 0~4095
IWDG_ReloadCounter();
IWDG_Enable();
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
}
void RCC_Configuration(void)
{
/ 定义枚举类型变量 HSEStartUpStatus /
ErrorStatus HSEStartUpStatus;
/* 复位系统时钟设置*/
RCC_DeInit();
/* 开启HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/* 等待HSE起振并稳定*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/* 判断HSE起是否振成功,是则进入if()内部 */
if(HSEStartUpStatus == SUCCESS)
{
/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* 设置FLASH延时周期数为2 */
FLASH_SetLatency(FLASH_Latency_2);
/* 使能FLASH预取缓存 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* 使能PLL */
RCC_PLLCmd(ENABLE);
/* 等待PLL输出稳定 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* 选择SYSCLK时钟源为PLL */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* 等待PLL成为SYSCLK时钟源 */
while(RCC_GetSYSCLKSource() != 0x08);
}
/* 打开APB2总线上的GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
//RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Periph_WWDG, ENABLE);
}
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1 , &USART_ClockInitStructure);
USART_InitStructure.USART_BaudRate = 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_Cmd(USART1,ENABLE);
}
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
#if PRINTF_ON
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(u8) ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
return ch;
}
#endif
#include “stm32f10x_it.h”
#include “stdio.h”
void EXTI0_IRQHandler(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_7,Bit_SET);
//EXTI_ClearFlag(EXTI_Line0); //清除此中断标志位,系统由于唤醒将直接复位
}
void SysTick_Handler(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));
}