文章目录
- 写在前面
- 电源
-
- 电压调节器
- 电源管理器
- 低功耗模式
-
- [**1. 运行模式(Run Mode)------ "全速行驶的燃油车"**](#1. 运行模式(Run Mode)—— “全速行驶的燃油车”)
- [**2. 睡眠模式(Sleep Mode)------ "汽车等红灯(怠速状态)"**](#2. 睡眠模式(Sleep Mode)—— “汽车等红灯(怠速状态)”)
- [**3. 停止模式(Stop Mode)------ "汽车熄火但保留了行车电脑记忆"**](#3. 停止模式(Stop Mode)—— “汽车熄火但保留了行车电脑记忆”)
- [**4. 待机模式(Standby Mode)------ "汽车彻底断电,拔掉电瓶"**](#4. 待机模式(Standby Mode)—— “汽车彻底断电,拔掉电瓶”)
- 低功耗模式下的自动唤醒(AWU)
- 备份寄存器(BKP)
- 实验
写在前面
这一篇内容包括两个内容,一个是PWR电源控制以及BKP备份寄存器。因为BKP的内容不多所以就合并到一起了。另外就是我与大家分享一个关于我的小插曲。在这最后我们同样还是会有个关于低功耗的小实验。原本我是不打算写在这里的。等我们学完之后就会知道stm32f103c8t6的芯片唤醒低功耗模式会有一些局限性。所以我上网查了有专门应对低功耗场景的芯片L0系列。这个芯片有一个LPUART,就是说他可以通过USART通信唤醒STOP模式(这些下面都会讲到)。但是我买来之后,发现官网没有相关SPL库,后来才知道,它只支持HAL库开发,博主尚未涉猎HAL库,所以只能放弃。然后看到官网有L1系列的SPL库,然后又买了stm32L151c8t6。当我建好工程项目的时候,发现L1系列的也不支持LPUART,唤醒手段和f103一样,只是主频低了。所以,最后还是选择用经典的f103c8t6作为此次的开发环境。
电源

STM32的工作电压(VDD)为2.0~3.6V。通过内置的电压调节器提供所需的1.8V电源。
当主电源VDD掉电后,通过VBAT脚为实时时钟(RTC)和备份寄存器提供电源。
解读一下上面的电源图示,详细内容还是参考官方的参考手册
-
ADC使用了独立的电源供电
可以在最上面可以看到 V D D A V_{DDA} VDDA供电区域中的A/D转换器,这是为了过滤和屏蔽来自印刷电路板上的毛刺干扰,另外复位模块我们不难理解。关于温度传感器和PLL(锁相环,用来对时钟进行倍频)。同样也是保证系统稳定运行的
-
中间部分
也就是MCU正常工作的地方由 V D D V_{DD} VDD同一进行供电
-
V B A T V_{BAT} VBAT部分
这就是我们后面要讲到的BKP部分,在我们的电路板上右上角有个引脚VBT就是这个,接入可以保证部分数据不丢失,但是保护的数据也十分有限。可以存储类似时间戳一类的数据,那么即使断电,我们的时间依然是准确的。
电压调节器
复位后调节器总是使能的。根据应用方式它以3种不同的模式工作。
- 运转模式:调节器以正常功耗模式提供1.8V电源(内核,内存和外设)。
- 停止模式:调节器以低功耗模式提供1.8V电源,以保存寄存器和SRAM的内容。
- 待机模式:调节器停止供电。除了备用电路和备份域外,寄存器和SRAM的内容全部丢失。
电源管理器
上电复位(POR)和掉电复位(PDR)
STM32内部有一个完整的上电复位(POR)和掉电复位(PDR)电路,当供电电压达到2V时系统既能正常工作。当VDD/VDDA低于指定的限位电压VPOR/VPDR时,系统保持为复位状态,而无需外部复位电路。关于上电复位和掉电复位的细节请参考数据手册的电气特性部分。

可编程电压检测器(PVD)
用户可以利用PVD对VDD电压与电源控制寄存器(PWR_CR)中的PLS2:0位进行比较来监控电源,这几位选择监控电压的阀值。通过设置PVDE位来使能PVD。电源控制/状态寄存器(PWR_CSR)中的PVDO标志用来表明VDD是高于还是低于PVD的电压阀值。该事件在内部连接到外部中断的第16线,如果该中断在外部中断寄存器中是使能的,该事件就会产生中断。当VDD下降到PVD阀值以下和(或)当VDD上升到PVD阀值之上时,根据外部中断第16线的上升/下降边沿触发设置,就会产生PVD中断。例如,这一特性可用于用于执行紧急关闭任务。

可以看到这两张图的电压都有两个阈值。这是为了防电压不稳定时在阈值附近波动
低功耗模式
在stm32f103c8t6中PWR中我们可以设置三种低功耗模式:
- SLEEP模式(内核和停止,所有外设包括Cortex-M3核心的外设继续工作)
- STOP模式(所有时钟停止)
- STANDBY模式(1.8V电源关闭)
除了提供给我们的三种低功耗模式,我们也可以自己通过设置系统参数来降低功耗
-
降低时钟频率

从这里我们可以看到,可以通过修改这里的宏来进行主频的配置,但是一般不建议修改,如果你修改了这里,你的程序逻辑也要相应的修改,比如延时1s,你如果改成36000000,那可能就是延时两秒。总的来讲,修改了系统主频,就是修改了系统的反应时间,所以相应的程序处理逻辑也要进行修改。 -
关闭APB和AHB总线上未被使用的外设时钟
这一点很好理解,其实就是你用的越少就越省电,空转肯定比用很多外设省电。但实际上就算程序空转也是十分耗电的。所以我们还是合理规划外设的使用情况下通过MCU提供给我们的低功耗方式

这三种模式的进入和唤醒,从代码上来讲是非常简单的。
睡眠模式(SLEEP)就是CPU停止工作,外设和时钟都在继续工作,所以只是一定程度上节省开销,但是总要好过修改主频的方式
停机模式(STOP)可以理解为保留了当前MCU所有程序运行的快照,当被唤醒时,可以继续之前的工作。
待机模式(STANDBY)这是最低功耗,只会保留备份寄存器的内容其他都会清空。如果在该模式唤醒,你会发现你的程序是从头执行的。
在这里就可以提到我开头的小插曲了
可以看到只有SLEEP模式是任一中断唤醒的,其他两种需要外部中断唤醒。在之前我们学习了DMA+IDLE接收数据的方式,本质上它节省了CPU的开销,也是降低了功耗,但是CPU仍然是在工作的,实际的耗电情况并没有明显改变。如果我们可以使用STOP模式让MCU深度睡眠。当有指令来的时候,再执行命令,这样可以极大的降低功耗。一个典型的例子就是我们的汽车钥匙或是遥控器。如果说在我们不使用的情况下它依然在空转那么很快就会没电了。但是如果采用低功耗就不一样了。
这是来自AI的例子:
为了让你直观地感受到STM32不同功耗模式下的能耗差别,我们以一个**"智能温湿度传感器"**(由一颗纽扣电池供电)为例。
假设这个传感器每隔一段时间需要唤醒,读取一次温湿度数据,然后通过串口发送给主机。在两次读取数据的漫长间隔中,它处于空闲状态。
以下是它在四种模式下的真实表现:
1. 运行模式(Run Mode)------ "全速行驶的燃油车"
- 状态:CPU全速运行,所有外设(ADC、串口等)都在工作。
- 能耗表现 :电流消耗在 mA(毫安)级别(例如 35mA)。
- 现实结果 :如果传感器一直在这个模式下"空转"等待下一次测量,一颗普通的纽扣电池(约220mAh)可能在 几个小时甚至几天内 就会被耗尽。
2. 睡眠模式(Sleep Mode)------ "汽车等红灯(怠速状态)"
- 状态:CPU(内核)停止工作,但定时器、ADC等外设还在继续运行。
- 能耗表现 :电流依然在 mA级别(例如 2~5mA)。
- 现实结果 :虽然CPU不干活了,但外设还在耗电。电池依然撑不过 几天。这种模式只适合极短时间的空闲。
3. 停止模式(Stop Mode)------ "汽车熄火但保留了行车电脑记忆"
- 状态:所有高速时钟关闭,但RAM和寄存器的数据被完整保留。
- 能耗表现 :电流骤降至 μA(微安)级别(例如 10~20μA)。
- 现实结果 :能耗比运行模式降低了成百上千倍。传感器在休眠时几乎不耗电,只有当RTC定时器报警或外部按键触发时才会醒来。在这种模式下,一颗纽扣电池可以支撑设备连续工作 几个月甚至大半年。
4. 待机模式(Standby Mode)------ "汽车彻底断电,拔掉电瓶"
- 状态:1.2V核心电源完全关闭,RAM里的数据全部丢失。
- 能耗表现 :达到极致,电流低至 1μA以下(例如 0.29μA)。
- 现实结果 :设备进入了深度休眠。唤醒后,单片机相当于重新上电复位,必须从头开始执行代码。在这种模式下,一颗纽扣电池足以让传感器在野外连续工作 一到两年。
低功耗模式下的自动唤醒(AWU)
RTC可以在不需要依赖外部中断的情况下唤醒低功耗模式下的微控制器(自动唤醒模式)。RTC提供一个可编程的时间基数,用于周期性从停止或待机模式下唤醒。通过对备份区域控制寄存器(RCC_BDCR)的RTCSEL1:0位的编程,三个RTC时钟源中的二个时钟源可以选作实现此功能。
- 低功耗32.768kHz外部晶振(LSE) :该时钟源提供了一个低功耗且精确的时间基准。(在典型情形下消耗小于1µA)
- 低功耗内部RC振荡器(LSI RC) :使用该时钟源,节省了一个32.768kHz晶振的成本。但是RC振荡器将少许增加电源消耗。
为了用RTC闹钟事件将系统从停止模式下唤醒,必须进行如下操作:
- 配置外部中断线17为上升沿触发。
- 配置RTC使其可产生RTC闹钟事件。
如果要从待机模式中唤醒,不必配置外部中断线17。
因为RTC的时钟源可由VBAT单独供电,所以它不依靠其他已经被关闭的时钟源,则可以实现唤醒操作
备份寄存器(BKP)
简介
备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问。
- 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
- 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。
BKP特性
-
stm32f103c8t6中有10后备寄存器(每个寄存器2字节)
-
用来管理防入侵检测并且具有中断功能的状态/控制寄存器
防入侵检测类似于一个保险箱,你拔掉了电源可以不用输入密码打开,但是设置了一个小开关,你打开会碰到,这个小开关是独立供电的不受影响,碰到之后就自毁。大概是这么个意思
比如你的产品里边,在BKP中存了一些核心的数据,那么有人想拆开连接你的芯片研究一下,拆开的那一瞬间,就可以触发,然后清空寄存器数据。
这里就是我的理解,详细内容可以查看手册
RTC校准
为方便测量,RTC时钟可以经64分频输出到侵入检测引脚TAMPER上。通过设置RTC校验寄存器(BKP_RTCCR)的CCO位来开启这一功能。通过配置CAL6:0位,此时钟可以最多减慢121ppm。关于RTC校准和如何提高精度,请看AN2604"STM32F101xx和STM32F103xx的RTC校准
实验
这篇实验我们可以结合上一个打印日期的实验结合起来。我们可以让MCU处于低功耗的模式,如果使用SLEEP模式我们可以通过USART,如果是STOP或STANDBY模式可以设置一个按键来触发外部中断。触发一次打印一次时间,这里的时间是不受影响的,因为RTC是独立供电的。或者也可以尝试使用闹钟。然后街上VBAT,每次唤醒都存储当前时间戳,这样即使断电,时间依然是准确的。
(另外这里要说明一下,如果你使用杜邦线直接接到3.3V,你是不能拔地线的,因为没有给他独立接地线,说白了就是只有正极没有负极,不要测试的时候一股脑都拔了)
在这个实验中可以把三种模式都试一下,代码不难,我就只简单演示一下sleep模式.代码都是沿用的前篇代码,只是需要一个__WFI();
c
#include "stm32f10x.h"
#include "Delay.h"
#include "../RTC.h"
#include "USART1.h"
#include <time.h>
extern volatile uint8_t flag;
int main(){
init_USART1();
init_RTC();
init_NVIC();
time_t tim;
while(1){
USART1_SendStr("wake up!\n");
if(flag){
tim = RTC_GetCounter() + 8 * 60 * 60; // 默认是伦敦时间,转换成北京时间要加8小时
USART1_SendStr(asctime(localtime(&tim)));
flag = 0;
}
__WFI();
}
}

可以看到如果没有休眠的话应该疯狂打印wake up。说明进入了休眠模式。我是使用的IDLE中断,所以输入任意字符会唤醒一次打印时间