很多单片机都有低功耗模式,STM32也不例外。在系统或电源复位以后,微控制器处于运行状态。运行状态下的HCLK为CPU提供时钟,内核执行程序代码。当CPU不需继续运行时,可以利用多个低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗,最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
STM32的低功耗模式有3种:
1)睡眠模式(CM3内核停止,外设仍然运行)
2)停止模式(所有时钟都停止)
3)待机模式(1.8V内核电源关闭)
在运行模式下,我们也可以通过降低系统时钟关闭APB和AHB总线上未被使用的外设的时钟来降低功耗。三种低功耗模式一览表见表21.1.1所示:
表21.1.1 STM32低功耗一览表
在这三种低功耗模式中,最低功耗的是待机模式,在此模式下,最低只需要2uA左右的电流。停机模式是次低功耗的,其典型的电流消耗在20uA左右。最后就是睡眠模式了。用户可以根据自己的需求来决定使用哪种低功耗模式。
现在仅对STM32的最低功耗模式-待机模式,来做介绍。待机模式可实现STM32的最低功耗。该模式是在CM3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。仅备份的寄存器和待机电路维持供电。
那么我们如何进入待机模式呢?其实很简单,只要按图21.1.1所示的步骤执行就可以了:
图1 STM32进入及退出待机模式的条件
图1还列出了退出待机模式的操作,从图1可知,我们有4种方式可以退出待机模式,即当一个外部复位(NRST引脚)、IWDG复位、WKUP引脚上的上升沿或RTC闹钟事件发生时,微控制器从待机模式退出。从待机唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位。
从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚,读取复位向量等)。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。
在进入待机模式后,除了复位引脚以及被设置为防侵入或校准输出时的TAMPER引脚和被使能的唤醒引脚(WK_UP脚),其他的IO引脚都将处于高阻态。
图1已经清楚的说明了进入待机模式的通用步骤,其中涉及到2个寄存器,即电源控制寄存器(PWR_CR)和电源控制/状态寄存器(PWR_CSR)。下面我们介绍一下这两个寄存器:
电源控制寄存器(PWR_CR),该寄存器的各位描述如图2所示:
图2 PWR_CR寄存器各位描述
这里我们通过设置PWR_CR的PDDS位,使CPU进入深度睡眠时进入待机模式,同时我们通过CWUF位,清除之前的唤醒位。电源控制/状态寄存器(PWR_CSR)的各位描述如图3所示:
图3 PWR_ CSR寄存器各位描述
二、这里主要说明RTC闹钟中断唤醒休眠
配置RTC前需知:
BKP:
RTC模块和时钟配置系统的寄存器是在后备区域的(即BKP),通过BKP后备区域来存储RTC配置的数据可以让在系统复位或待机模式下唤醒后 RTC里面配置的数据维持不变。
PWR:
PWR为电源的寄存器,我们需要用到的是电源控制寄存器(PWR_CR),通过使能PWR_CR的DBP位来取消后备区域BKP的写保护。
RTC :
由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频
模块,它可编程产生最长为1 秒的RTC时间基准TR_CLK 。RTC的预分频模块包含了一个20位的
可编程分频器(RTC 预分频器) 。如果在RTC_CR寄存器中设置了相应的允许位,则在每个实时时钟(RTC)TR_CLK 周期中RTC产生一个中断( 秒中断) 。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK 周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。
RTC闹钟唤醒事件发生时,同时进入闹钟中断,必须在初始化时与外部中断线17关联
如果仅想退出待机模式,RTC闹钟事件已经足够,不必与外部中断线17关联
退出待机模式后,接下来的流程类似于按下复位按键,程序会从头开始执行
RTC的配置如下:
- NVIC_InitTypeDef NVIC_InitStructure;
- EXTI_InitTypeDef EXTI_InitStructure;
- //闹钟中断接到第17线外部中断
- EXTI_ClearITPendingBit(EXTI_Line17);
- EXTI_InitStructure.EXTI_Line = EXTI_Line17;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;
- EXTI_Init(&EXTI_InitStructure);
- //设置RTC闹钟中断
- NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
本例使用内部晶振LSI 40KHZ,如果使用外部LSE 为32.768khz void RTC_Configuration(void)
{
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE );// 通过设置寄存器RCC_APB1ENR的PWREN 和BKPEN位来打开电源和后备接口的时钟
PWR_BackupAccessCmd(ENABLE);//电源控制寄存器(PWR_CR) 的DBP位来使能对后备寄存器和RTC的访问
BKP_DeInit();初始化复位BKP寄存器
RCC_LSEConfig(RCC_LSE_OFF);//关闭LSE
RCC_LSICmd(ENABLE);//使能LSI为40khz
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);//设置后需要等待启动
{
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);////选择LSI为RTC设备 的 时钟,LSI为40khz
RCC_RTCCLKCmd(ENABLE);;//使能RTC
RTC_WaitForSynchro();//等待同步
RTC_SetPrescaler(310); //设置预分频值RTC period = RTCCLK/RTC_PR = (40KHz)/(310+1) 约等于7.775ms
RTC_WaitForLastTask();/* 1. 查询RTOFF位,直到RTOFF的值变为1 */
RTC_ITConfig(RTC_IT_ALR, ENABLE); //使能闹钟中断
RTC_WaitForLastTask();
}
闹钟唤醒中断代码:
void RTCAlarm_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
{
/* Clear EXTI line17 pending bit */
EXTI_ClearITPendingBit(EXTI_Line17); // 清EXTI_Line17挂起位
/* Check if the Wake-Up flag is set */
if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)// 检查唤醒标志是否设置
{
/* Clear Wake Up flag */
PWR_ClearFlag(PWR_FLAG_WU);
}
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Clear RTC Alarm interrupt pending bit */
RTC_ClearITPendingBit(RTC_IT_ALR);
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
下面写进去闹钟中断后执行的代码
}
}
休眠时间长短封装函数
void Sleep(uint AlarmValue)
{
/* Wait till RTC Second event occurs */
RTC_ClearFlag(RTC_FLAG_SEC);
while(RTC_GetFlagStatus(RTC_FLAG_SEC) == RESET);
RTC_SetAlarm(RTC_GetCounter()+ AlarmValue); //当前时间+预警时间
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Request to enter STOP mode with regulator in low power mode*/
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
/* Configures system clock after wake-up from STOP: enable HSE, PLL and select
PLL as system clock source (HSE and PLL are disabled in STOP mode) */
SYSCLKConfig_STOP();
}
休眠时间计算
休眠时间主要是看这个 RTC_SetAlarm(RTC_GetCounter()+ AlarmValue); RTC_SetPrescaler(value); 休眠时间AlarmValue*预分频算出来的时间。