Stm32的低功耗模式
3种低功耗模式:
**1.睡眠模式:**内核停止,外设如NVIC,系统时钟Systick仍运行。
**2.停止模式:**所有时钟都已停止。1.8V内核电源工作。
PLL,HIS和HSE RC振荡器功能禁止。
寄存器和SRAM内容保留。
3.待机模式:1.8V内核电源关闭。
只有备份寄存器和待机电路维持供电。
寄存器和SRAM内容全部丢失。实现最低功耗。
在运行模式下,可以通过下面方式降低功耗:
① 降低系统时钟。
② 关闭APB和AHB总线上未被使用的外设时钟。
低功耗模式的进入与唤醒:
注意:每种模式的唤醒中断有所差别,待机模式理想状态下,只需要2uA电流。停机模式下典型电流为20uA。
待机模式:
待机模式初始化代码:
//初始化待机模式
void Standy_Init(void)
{
SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)
RCC->APB1ENR|=1<<28; //使能电源接口时钟
PWR->CR|=1<<1; //CPU进入待机模式使能
PWR->CR|=1<<2; //清除WKUP唤醒标志位,防止在使能时产生唤醒事件
PWR->CSR|=1<<8; //设置PA0唤醒
WFI_SET(); //执行WFI指令
其中WFI_SET()代码:
//THUMB指令不支持汇编内联 //采用如下方法实现执行汇编指令WFI void WFI_SET(void) { __ASM volatile("wfi"); }
上面的SCB->SCR寄存器stm32中文参考手册没有,在编程手册上有提到:
这个是系统寄存器中的一个不需要了解太多,设置SLEEPDEEP位就行。其他寄存器在中文参考手册中有详细解释。
注意:初始化待机模式时也要开启电源端口时钟 RCC->APB1ENR|=1<<28; //使能电源接口时钟
下面为待机唤醒实现的代码:
#include "wkup.h"
#include "delay.h"
#include "led.h"
//初始化待机模式
void Standy_Init(void)
{
RCC->APB2RSTR|=0X01FC;//复位所有IO口
SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)
RCC->APB1ENR|=1<<28; //使能电源接口时钟
PWR->CR|=1<<1; //CPU进入待机模式使能
PWR->CR|=1<<2; //清除WKUP唤醒标志位,防止在使能时产生唤醒事件
PWR->CSR|=1<<8; //设置PA0唤醒
WFI_SET(); //执行WFI指令
}
void WKUP_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC->APB2ENR|=1<<2; //使能时钟
GPIOA->CRL&=0xfffffff0; //清除配置位
GPIOA->CRL|=0x00000008; //下拉输入
GPIOA->IDR&=0xfffffffe; //设置为下拉
RCC->APB2ENR|=1<<0; //打开复用功能时钟
AFIO->EXTICR[0]&=0xfffffff0; //清零配置,并配置中断线连接到PA0
EXTI->RTSR|=0x01; //上升沿中断
EXTI->IMR|=0x01; //开启中断线
//开启中断
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
if(Check_Key()==0)Standy_Init(); //进入待机模式
}
u8 Check_Key(void)
{
u8 t;
LED0=0; //亮灯DS0
while(1)
{
if(WK_UP)
{
t++;
delay_ms(30);
if(t>=100)
{
LED0=0;
return 1;
}
}
else{
LED0=1;
return 0;
}
}
}
void EXTI0_IRQHandler()
{
EXTI->PR=1<<0; //清除LINE10上的中断标志位
if(Check_Key())//关机?
{
Standy_Init();
}
}
#include "delay.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "wkup.h"
#include "sys.h"
#include "lcd.h"
int main()
{
LED_Init();
KEY_Init();
delay_init();
uart_init(115200); //串口初始化为115200
WKUP_Init();
LCD_Init();
POINT_COLOR=RED;
LCD_ShowString(30,70,200,16,16,"WKUP TEST");
while(1)
{
LED0=!LED0;
delay_ms(500);
}
}
功能:初始化时进入待机模式,LCD屏幕关闭,当PA0口的WK_UP按键按下3秒时屏幕唤醒。
实现过程:开始进入待机模式,其中Check_Key()==0的判断是为下次唤醒时不初始化进入待机模式准备的,因为待机唤醒后CPU重头执行程序。按下WK_UP 3秒后屏幕跳出按键的while(1)的循环继续执行任务,其实WK_UP 一按下去检测到上升沿信号立马就唤醒了,只是按键while(1)延时3秒后才执行下面的初始化以及后面的任务。再一次按下Wk_UP按键进入外部中断,在按键的Check_Key()函数延时下3秒后才进入待机模式。唤醒时之所以没有进入外部中断是因为CPU没有启动
低功耗----停止模式
测试代码:
停止模式初始化
void Stop_Mode()
{
SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)
PWR->CR|=0<<1; //清除待机模式使能位
PWR->CR|=1<<0; //使能停机模式
WFI_SET(); //执行WFI指令
}
打开PA0中断作为唤醒停止模式
void WKUP_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC->APB2ENR|=1<<2; //使能时钟
GPIOA->CRL&=0xfffffff0; //清除配置位
GPIOA->CRL|=0x00000008; //下拉输入
GPIOA->IDR&=0xfffffffe; //设置为下拉
RCC->APB2ENR|=1<<0; //打开复用功能时钟
AFIO->EXTICR[0]&=0xfffffff0; //清零配置,并配置中断线连接到PA0
EXTI->RTSR|=0x01; //上升沿中断
EXTI->IMR|=0x01; //开启中断线
//开启中断
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// if(Check_Key()==0)Stop_Mode(); //进入待机模式
}
在中断中加入Systemlnit()是初始化系统时钟为72MHz启用外部时钟,停止模式所有的时钟都停止,且CPU1.8v区全部不工作,所以停止退出后使用的是内部RC时钟。
void EXTI0_IRQHandler()
{
SystemInit();
EXTI->PR=1<<0; //清除LINE10上的中断标志位
}
我用的是PA0外部中断唤醒停止模式,通过按键进入停止模式;下面的 t 变量是测试停止模式中SRAM不断电而写的
int main()
{
u16 p;
LED_Init();
KEY_Init();
delay_init();
uart_init(115200); //串口初始化为115200
WKUP_Init();
LCD_Init();
POINT_COLOR=RED;
LCD_ShowString(30,70,200,16,16,"STOP TEST:");
while(1)
{
LED0=!LED0;
delay_ms(500);
p++;
LCD_ShowNum(110,70,p,3,16);
if(KEY1==0)
{
//EXTI->PR=0XFFFFF;
delay_ms(10);
if(KEY1==0)
{
Stop_Mode();
LED1=0;}
}
}
}
对比待机模式,停止模式应该注意的细节:
停止模式的SRAM以及寄存器的值在进入停止模式时保持不变,也就是说在退出停止模式后程序在之前执行到哪一步的接着往下执行,这是因为CPU的程序指针保留为进入停止模式时的值,恢复后继续下一步;而待机模式由于寄存器断电不工作,所以程序指针在退出时从头开始执行程序。
睡眠模式:
初始化代码:
//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI
void WFI_SET(void)
{
__ASM volatile("wfi");
}
只需要这一句命令就可以初始化为睡眠模式。
注意:睡眠模式只有CPU停止了工作,只是不运行程序,停止了而已。
上一篇:Stm32的Flash模拟EEPROM与BOOT基本了解
下一篇:Stm32的ADC功能介绍及相关代码
推荐阅读




推荐帖子
- CAN总线的问题
- 这几天一直都在忙,而且忙到很烦, 产品出了点问题,在家里怎么都不能再现,很多天过去了, 今天发现了一点,可能正是问题所在, 我用同一个CAN接口,不同的两个buffer发送了两组数据, 甚至调用的发送子函数都是一样的,出人意料,今天竟然出现只发出了其中一组数据的情况 接收数据,是用第三方的工具,应该是正确的结果, 求大虾指点,为什么 有经验的速来,谢谢:(CAN总线的问题
-
HOHO
单片机
- 新塘M030G开发板的ISP_UART升级操作说明
- 新唐的MCU都提供的ISP功能,且提供提供了相关的工具和程序,很多时候因为资料比较杂,且项目紧急,没办法慢慢的来研究其ISP升级机制,刚好笔者手上有个M030G的评估版,用来指导说明ISP通过串口升级的操作方法;可方便用户快速熟悉并使用; 新塘M030G开发板的ISP_UART升级操作说明
-
火辣西米秀
国产芯片交流
- 能否用open打开打开usb节点?
- 本信息来自合作QQ群:armlinuxfpga嵌入0群49900581(超级群)群主在坛子里ID:wangkj 我问一下各位大虾, 我把U盘插入linux系统的电脑时有一个设备U盘节点/dev/sdb1 当我用open函数打开时打不开 open("/dev/sdb1",O_RDWR); 返回一个小于零的数 难道不能用open打开打开usb节点?能否用open打开打开usb节点?
-
ic_李余荣
嵌入式系统
- 函数信号发生器的问题
- 要做一个函数信号发生器用凌阳061a和max038max038的fadj口调节频率-2.4v到2.4v可调用061的dac口输出的是0-3mA电流怎样转换成2.4v到2.4v可调电压谢谢啦并诚交电路设计能人异士为好友如果可能诚心拜师非诚勿扰联系邮箱lian.sun.hai@163.com函数信号发生器的问题
-
younha
嵌入式系统
- 电子测量仪器原理与使用
- 内容简介:本书系统地阐述了各种电子测量仪器的工作原理与使用。内容包括:基础知识、测量用信号发生器、电子电压表、电子示波器、电子计数器、元件参数测试仪、晶体管特性图示仪、数字集成电路测试仪、频谱分析仪、频率特性测试仪(扫频仪)、网络分析仪、逻辑分析仪、虚拟仪器等.电子测量仪器原理与使用
-
心仪
测试/测量
- 【phyBOARD-i.MX 8M Plus 开发板】三:Demo例程编译下载及运行
- phyBOARD-i.MX8MPlus开发板的编译环境在虚拟机中已经搭建好了,然后由于是Linux的系统,Demo例程需要交叉编译后下载至开发板后才能执行。 1、虚拟机环境设置 由于是德国版本的乌班图,需要设置语音和键盘,否则会出现上次评测中无法输入/的情况 点击右侧上方的下三角,出现界面后,点击配置按钮 在配置界面中选择语音,需要把字体和键盘都改成us 如下图,中间可能需要重启 语音和键盘更改后,就可以正常使用了,不过,没有中文支持。 2
-
kit7828
开发板测评专版