一、PWR
1.1PWR簡介
PWR(Power Control)電源控制
PWR負責管理STM32內部的電源供電部分,可以實現可編程電壓監測器和低功耗模式的功能
可編程電壓監測器(PVD)可以監控VDD電源電壓,當VDD下降到PVD閥值以下或上升到PVD閥值之上時,PVD會觸發中斷,用于執行緊急關閉任務
低功耗模式包括睡眠模式(Sleep)、停機模式(Stop)和待機模式(Standby)(功耗逐級降低,喚醒時間逐級變長),可在系統空閑時,降低STM32的功耗,延長設備使用時間
1.2電源框圖
1. VDDA供電區 (模擬電源域)
功能:為芯片內部所有模擬模塊供電的獨立電源區域。
供電引腳:由獨立的?VDDA?和?VSSA?引腳供電。
主要負載:
模數轉換器 (ADC)
數模轉換器 (DAC)(如果支持)
內部RC振蕩器 (HSI, LSI)、鎖相環 (PLL)
電壓參考緩沖 (VREF+ / VREF-)(在某些型號上由VDDA引出)
設計要點:
必須連接:即使不使用任何模擬功能,VDDA也必須連接到VDD(通常通過一個磁珠或低阻值電阻隔離),否則芯片無法正常工作。
去耦和濾波:為了獲得最佳的ADC性能,VDDA和VSSA必須并聯高頻和低頻去耦電容(例如100nF + 1uF),并盡可能靠近芯片引腳,以濾除來自數字電路的噪聲。
電源質量:ADC的轉換精度直接依賴于VDDA的電壓穩定性和純凈度。如果VDDA上有噪聲,ADC的讀數也會產生波動。
2. VDD供電區
來源:直接從芯片的?
VDD
/VSS
?引腳接入。供電目標:
I/O 引腳:所有數字I/O口的驅動電源。
部分模擬電路:雖然模擬部分主要由VDDA供電,但一些與I/O相關的模擬邏輯(如輸入保護二極管)也可能連接到VDD。
待機電路(喚醒邏輯,IWDG)
電壓調節器:連接1.8V供電區域
特點:這是芯片的主電源入口。在設計PCB時,必須在每個?
VDD
?引腳附近放置一個去耦電容(通常100nF),以濾除高頻噪聲,提供穩定電流。
3. 1.8V供電區域 (數字電源域)
功能:芯片數字核心邏輯的供電區域,是芯片運行的主要動力源。
供電來源:
在大多數STM32(除某些超低功耗型號外)中,VDD電壓(如3.3V)并不直接供給內核。
而是通過一個內部電壓調節器(穩壓器)將VDD降壓到一個穩定的1.8V(或1.2V,取決于產品系列和工作頻率),再為這個區域供電。
主要負載:
CPU內核 (Cortex-M系列核心)
數字外設?(如GPIO、SPI, I2C, USART, Timers等)
內部SRAM和Flash存儲器
設計要點:
VDD引腳:為整個數字部分供電,包括I/O口和內部穩壓器。需要良好的去耦。
低功耗模式:在停止等模式下,PWR可以關閉或降低該穩壓器的輸出,以大幅降低靜態功耗。
此1.8V區域在芯片內部產生,用戶無法直接從外部測量或供電。
4. 后備供電區 (Backup Domain)
功能:一個獨立的供電區域,用于在主電源(VDD/VBAT)丟失時,保存最關鍵的數據和維持最基本的時基功能。
供電來源:由一個特殊的電源選擇電路控制,其電源來自:
VDD(當主電源存在時)
VBAT(當低電壓檢測器檢測到主電源VDD斷開時,自動切換到VBAT引腳)
主要負載:
實時時鐘 (RTC):即使主MCU斷電,RTC也可以繼續走時。
備份寄存器 (Backup Registers):一小塊由VBAT維持的SRAM,通常為16-32字節,用于存儲關鍵數據(如設備序列號、校準參數、運行狀態等)。
喚醒邏輯:用于從待機模式通過RTC鬧鐘或WKUP引腳喚醒整個系統。
設計要點:
VBAT引腳:必須連接。如果應用中沒有備用電池(如紐扣電池),強烈建議將VBAT引腳通過一個100nF電容連接到VSS,并同時通過一個二極管(如1N4148)連接到VDD。這樣可以確保主電源存在時由VDD為備份域供電,主電源斷開時則由電容短暫維持(時間很短,僅用于安全關機)。
寫保護:要修改備份域中的寄存器(RTC配置、備份寄存器),必須先取消其寫保護。
域隔離:備份域與其他域通過特殊的開關隔離,只有在特定條件下才能被訪問,這進一步保證了其數據安全。
5. 總結與關鍵注意事項
供電區域 | 來源 | 供電目標 | 設計要點 |
---|---|---|---|
VDD | 外部電源 | I/O引腳,部分內部邏輯 | 充分去耦,每個VDD引腳一個100nF電容 |
VDDA | 獨立清潔電源 | ADC, DAC, VREF+ | 必須通過磁珠/電感與VDD隔離,加強濾波 |
1.8V域 | 內部LDO(來自VDD) | CPU, 內存, 數字外設 | 低功耗模式的控制核心 |
VBAT | 外部電池 | RTC, 備份寄存器, LSE | 保證主電源掉電后關鍵功能不丟失 |
1.3上電復位(POR)和掉電復位(PDR)
基本概念
上電復位(Power-On Reset, POR):在芯片從無電到上電的過程中,當供電電壓VDD從0V開始上升,達到一個特定的觸發閾值(VPOR)?時,芯片會產生一個復位信號,將整個系統保持在復位狀態,直到電源電壓穩定到一個可靠的水平。
掉電復位(Power-Down Reset, PDR):在芯片正常工作后,如果因為某種原因(如電源干擾、電池耗盡)導致VDD電壓下降,當電壓低于一個特定的觸發閾值(VPDR)?時,芯片會產生一個復位信號,防止CPU和外設在電壓不足的情況下執行錯誤操作。
在STM32中,POR和PDR電路通常被集成在一起,統稱為POR/PDR電路。它們是一個完全由模擬硬件實現的功能,不需要任何軟件配置,只要接了VDD電源就會自動工作。
POR的40mV遲滯(確保電源穩定和等待時鐘穩定)
是什么:遲滯是一種經典的電路設計技術,用于防止比較器在閾值點附近因噪聲或微小波動而產生反復翻轉(振蕩)。
如何工作:
VPOR_up?(上升閾值):當VDD電壓從0V開始上升時,必須達到VPOR(例如,約1.8V)這個閾值點,POR電路才會解除復位信號。
VPOR_down?(下降閾值):當VDD電壓從正常值下降時,必須降到比VPOR低40mV(例如,約1.76V)的點,POR電路才會重新斷言(Assert)復位信號。
1.4可編程電壓監測器(預警)
基本概念
可編程電壓監測器(Programmable Voltage Detector, PVD)?是一個可以由軟件配置的電源電壓監測模塊。它持續將VDD電壓與一個由軟件設定的閾值(PLS[2:0]
)進行比較。
?PVD閾值
是什么:PVD的閾值不是固定的,而是由軟件通過配置PWR_CR寄存器的
PLS[2:0]
位來動態選擇的。閾值等級:STM32提供了多個可選的閾值,覆蓋了一個常見的電壓范圍(例如,從2.0V到2.9V,具體范圍和步進因產品系列而異)。這允許開發者根據實際供電電壓(如3.3V系統或2.5V系統)來設置一個合理的預警點。
PVD的100mV遲滯(防止振蕩,緩沖區)
是什么:與POR類似,PVD的比較器也內置了遲滯功能,但其遲滯電壓典型值為100mV。
如何工作:
假設軟件設置的PVD閾值是?2.8V。
下降沿:當VDD電壓從高處下降到2.8V時,PVD輸出觸發,標志位置位,并可產生中斷。
上升沿:之后,如果VDD電壓又從低處回升,它必須達到?2.8V + 100mV = 2.9V?時,PVD輸出才會解除,標志位清零,并可再次產生中斷。
POR/PDR 與 PVD 的對比總結
特性 | POR/PDR | PVD |
---|---|---|
本質 | 硬件自動保護機制 | 軟件可配置的預警機制 |
功能 | 保證可靠上電和防止欠壓運行 | 監測電壓變化,提供早期預警 |
控制 | 完全由模擬硬件實現,無需配置(固定1.9V) | 需要通過軟件配置閾值和外部中斷(2.2V~2.9V) |
響應 | 產生復位信號,觸發系統復位,強制MCU重啟 | 觸發中斷或事件,由軟件決定如何處理 |
速度 | 響應極快,是最后防線 | 響應較快,但需軟件處理時間 |
關系 | “最后的安全衛士” | “哨兵”,為衛士提供預警 |
遲滯 | 典型40mV,防止電源噪聲導致反復復位 | 典型100mV,防止電壓波動導致中斷風暴 |
1.5低功耗模式
功耗從高到低,喚醒速度從快到慢:睡眠→停止→待機
1.睡眠模式 (Sleep Mode)
實現機制:執行
WFI
(Wait for Interrupt)或WFE
(Wait for Event)指令后,內核停止執行,CPU時鐘關閉。但所有外設的時鐘仍然正常運行,NVIC保持工作。功耗:功耗降低主要來自CPU核心本身。整體功耗相對較高。
喚醒:
任何外設中斷(如果使用
WFI
)或事件(如果使用WFE
)都可喚醒。喚醒時間極短,幾乎無延遲,因為時鐘系統仍在運行,CPU恢復時鐘后即可繼續執行下一條指令。
適用場景:處理完任務后,短暫等待下一次中斷,且對喚醒延遲要求極高的場合。
睡眠模式注意點:
- 執行完WFI/WFE指令后,STM32進入睡眠模式,程序暫停運行,喚醒后程序從暫停的地方繼續運行
- SLEEPONEXIT位決定STM32執行完WFI或WFE后,是立刻進入睡眠,還是等STM32從最低優先級的中斷處理程序中退出時進入睡眠
- 在睡眠模式下,所有的I/O引腳都保持它們在運行模式時的狀態
- WFI指令進入睡眠模式,可被任意一個NVIC響應的中斷喚醒
- WFE指令進入睡眠模式,可被喚醒事件喚醒
2. 停止模式 (Stop Mode)
實現機制:
PDDS位=0,停止模式
SLEEPDEEP=1
關閉整個1.8V供電區域的時鐘,包括CPU和所有外設的時鐘。
可選擇關閉內部主穩壓器(LPDS位=0,電壓調節器開啟,LPDS位=1,調壓器進入低功耗模式),以進一步省電。
可選是否保留IO口狀態。
所有寄存器和SRAM的內容保持不變。
功耗:功耗顯著降低,可達微安(μA)級別。
喚醒:
由外部復位(NRST引腳)、RTC鬧鐘/事件、RTC入侵事件、RTC喚醒事件、多個EXTI線(外部中斷,對應特定引腳)喚醒。
喚醒后,系統時鐘默認切換為HSI(內部多速RC振蕩器),需要軟件重新配置時鐘樹到想要的速度。程序從停止指令后的下一條指令開始執行。
適用場景:需要長時間休眠、定期喚醒采樣、且需保持當前程序上下文(變量值)的場合。是平衡功耗和靈活性的最佳選擇。
停止模式注意點:
- 執行完WFI/WFE指令后,STM32進入停止模式,程序暫停運行,喚醒后程序從暫停的地方繼續運行
- 1.8V供電區域的所有時鐘都被停止,PLL、HSI和HSE被禁止,SRAM和寄存器內容被保留下來
- 在停止模式下,所有的I/O引腳都保持它們在運行模式時的狀態
- 當一個中斷或喚醒事件導致退出停止模式時,HSI被選為系統時鐘
- 當電壓調節器處于低功耗模式下,系統從停止模式退出時,會有一段額外的啟動延時
- WFI指令進入停止模式,可被任意一個EXTI中斷喚醒
3. 待機模式 (Standby Mode)
實現機制:
PDDS位=1,待機模式
SLEEPDEEP=1
最徹底的模式。關閉1.8V供電區域(整個數字電路域)。
除了備份域(RTC、備份寄存器)和喚醒邏輯,其他部分全部斷電。
SRAM和寄存器內容全部丟失(備份寄存器除外)。
功耗:功耗最低,可達微安(μA)甚至納安(nA)級別。
喚醒:
由外部復位(NRST引腳)、RTC鬧鐘/事件、RTC入侵事件、WKUP引腳(PA0)的上升沿、獨立看門狗(IWDG)復位喚醒。
喚醒后相當于一次軟復位,芯片從頭開始執行程序(復位向量地址0x0000_0000)。可以通過檢查PWR_CSR寄存器的
SBF
(Standby Flag)標志位來判斷是否由待機模式喚醒。
適用場景:需要極低功耗、長時間休眠,且每次喚醒都作為一次全新啟動的場合。例如,每天只上報一次數據的遠程傳感器。
待機模式注意點:
- 執行完WFI/WFE指令后,STM32進入待機模式,喚醒后程序從頭開始運行
- 整個1.8V供電區域被斷電,PLL、HSI和HSE也被斷電,SRAM和寄存器內容丟失,只有備份的寄存器和待機電路維持供電
- 在待機模式下,所有的I/O引腳變為高阻態(浮空輸入)
- WKUP引腳的上升沿、RTC鬧鐘事件的上升沿、NRST引腳上外部復位、IWDG復位退出待機模式
4. 模式選擇
執行WFI(Wait For Interrupt)或者WFE(Wait For Event)指令后,STM32進入低功耗模式
5. 模式對比總結表
特性 | 睡眠模式 (Sleep) | 停止模式 (Stop) | 待機模式 (Standby) |
---|---|---|---|
功耗 | 中 | 低 | 極低 |
喚醒時間 | 極短?(僅CPU恢復時鐘) | 短 (需時鐘重啟) | 長 (完全復位) |
程序執行上下文 | 保持?(從下條指令繼續) | 保持?(從下條指令繼續) | 丟失?(從頭開始執行) |
SRAM/寄存器內容 | 保持 | 保持 | 丟失 (備份域除外) |
時鐘狀態 | 僅CPU時鐘停 | 所有1.8V域時鐘停 | 1.8V域斷電 |
主要喚醒源 | 任意中斷/事件 | EXTI線、RTC事件 | WKUP引腳、RTC事件、NRST |
應用場景 | 短暫空閑,快速響應 | 定期采樣,保持狀態 | 超長待機,復位啟動 |
6. 重要設計注意事項
GPIO配置:在進入Stop/Standby模式前,必須將所有不用的GPIO設置為模擬輸入模式。懸空的IO引腳如果被配置為浮空輸入,會因漏電流而顯著增加功耗。
未使用外設:關閉所有不需要的外設時鐘。
調試接口:低功耗模式可能會禁用調試器(如ST-Link)的連接。通常喚醒后才能重新連接。有些模式支持“調試駐留”功能,允許在低功耗下保持調試連接,但會略微增加功耗。
測量功耗:精確測量功耗時,需將調試器斷開,僅通過電源供電進行測量。
二、修改主頻頻率代碼
文件system_stm32f10.c中
此文件是只讀文件,若要修改,需要打開工程文件夾,打開文件所在位置,右鍵——屬性——只讀選項去除
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)#if是預編譯,用來兼容不同型號的設備
若define后面有效,就else上面有效
否則#else,即下面代碼有效我的設備時F10F3C8T6 中容量,非超值系列,因此查看else下方代碼,由此來修改主頻頻率
此時主頻頻率時72MHz/* #define SYSCLK_FREQ_HSE HSE_VALUE */#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif主程序代碼int main(void)
{ OLED_Init();OLED_ShowString(1,1,"SYSCLK:");OLED_ShowNum(1,8,SystemCoreClock,8);while(1){OLED_ShowString(2,1,"running");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(500);}
}
配置時鐘的流程:
①system_Init()函數→啟動HSI+各種缺省配置——調用SetSysClock()分配函數
②SetSysClock()分配函數→選擇解除不同的宏定義,從而執行不同的配置參數SerSysClockTo72等函數——進行配置主頻頻率(例:To72——HSE鎖相環輸入——HSE9倍頻——HSE鎖相環輸出位主頻——主頻72M)
三、睡眠模式+串口發送接收
(再次運行需要按住復位鍵倆秒+點擊運行+松手)
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "serial.h"
#include "stdio.h"
uint16_t Rxdata;在此工程基礎上,加一個低功耗的代碼假設用STM32做一個下位機
下位機接收電腦串口發送過來的指令,后執行相應的功能
電腦隨時都可能通過串口發送指令靠中斷觸發,沒有中斷就無用的代碼,可以加入一個低功耗模式——睡眠模式,其他模式都不行int main(void)
{ OLED_Init();serial_init();OLED_ShowString(1,1,"RXdata:");while(1){if(serial_getRxfalg()==1){Rxdata=serial_getRXdata();serial_sendbyte(Rxdata);}OLED_ShowHexNum(1,8,Rxdata,2);OLED_ShowString(2,1,"Running");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(500);--------------------------------------------------------------------------------SCB->SCR=0x………………//此種寄存器方式配置
__WFI();//中斷喚醒}
}
僅需加入__WFI即可進入睡眠模式
若想要配置深度睡眠模式還是睡眠模式,可以查看手冊STM32F10XXX.Cortex-M3編程手冊——4.4.6System control register(SCB_SCR),在程序中,用操作寄存器的方式實現
SEVEONPEND=0,事件喚醒睡眠模式需要配置的位
SLEEPDEEP=0,睡眠模式;=1,深度睡眠模式
SLEEPONEXIT=0,立刻睡眠;=1,等中斷結束睡眠
程序執行流程:
①初始化,串口配置好,進入主循環,檢查標志位,Running閃爍一次,在主循環最后執行__WFI(),執行WFI,CPU立刻睡眠
②CPU睡眠,各個外設運行狀態,等到串口發送數據,USART接收到數據,產生中斷,喚醒CPU,睡眠模式喚醒后,程序在暫停的地方繼續運行
③因此,程序運行到WFI之后,但喚醒之后,終端立刻申請,所以程序在條回到while循環開頭之前,先進入USART中斷函數,讀取數據,置R下Flag,清除RXNE,回到主循環開頭,此時RxFlag剛置1,if成立,執行數據回傳和顯示功能
④喚醒功能執行完,Running閃爍一次,程序再次來到WFI位置,CPU再次進入睡眠……
四、停止模式+對射式紅外傳感器計次
4.1PWR外設庫函數:
1.恢復缺省配置
void PWR_DeInit(void);
2.使能后備區域的訪問
void PWR_BackupAccessCmd(FunctionalState NewState);
3.與PVD相關的函數,PVD使能
void PWR_PVDCmd(FunctionalState NewState);
4.與PVD相關的函數,配置PVD的閾值電壓
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);
5.使能位于PA0位置的WakeUp引腳(待機模式用Wakeup上升沿喚醒)
void PWR_WakeUpPinCmd(FunctionalState NewState);
6.進入停止模式
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
7.進入待機模式
void PWR_EnterSTANDBYMode(void);
8.獲取標志位
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
9.清除標志位
void PWR_ClearFlag(uint32_t PWR_FLAG);
4.2代碼書寫
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "countSensor.h"外部中斷不需要時鐘
在硬件層面沒有EXTI,只有內部中斷和外部中斷,
外部中斷可用停機模式,內部中斷只能用睡眠模式
在代碼里無EXTI時鐘參數,這就是EXTI能在時鐘關閉的情況下工作的原因int main(void)
{ OLED_Init();CountSensor_Init();
--------------------------------------------------------------------------------------RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);OLED_ShowString(1,1,"count");while(1){ OLED_ShowSignedNum(1,7,count,5);OLED_ShowString(2,1,"Running");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(500);---------------------------------------------------------------------------------------PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);/*復位后第一個Running很快,后面就變慢了是因為推出停止模式后,HSI被選為系統時鐘SystemInit函數里配置的是72M主頻,后續的HSI是8M,因此運行時間變慢只需要在后面重新調用SystemInit函數,重新啟動HSE,配置72M主頻即可*/SystemInit();}}
五、待機模式+實時時鐘
任務一、設定鬧鐘
在while上設定,每次復位后設定鬧鐘值
任務二、加入待機模式
使用PWR外設之前,開啟時鐘,確保代碼獨立性
任務三、
wakeup引腳喚醒功能,隨時用GPIO引腳,但不需要GPIO初始化
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "My_RTC.h"int main(void)
{ OLED_Init();MyRTC_Init();RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);OLED_ShowString(1, 1, "CNT:");//秒計數器OLED_ShowString(2, 1, "ALR:");//鬧鐘值OLED_ShowString(3, 1, "ALRF:");//鬧鐘標志位/*使能WKUP引腳*/PWR_WakeUpPinCmd(ENABLE);//使能位于PA0的WKUP引腳,WKUP引腳上升沿喚醒待機模式uint32_t Alarm=RTC_GetCounter()+10;RTC_SetAlarm(Alarm);//只寫寄存器OLED_ShowNum(2,6,Alarm,10);while(1){OLED_ShowNum(1, 6, RTC_GetCounter(), 10); //顯示32位的秒計數器/*鬧鐘標志位是否置1*/OLED_ShowNum(3,6,RTC_GetFlagStatus(RTC_FLAG_ALR),1);OLED_ShowString(4,1,"Running");Delay_ms(500);OLED_ShowString(4,1," ");Delay_ms(500);OLED_ShowString(4, 9, "STANDBY");//OLED閃爍STANDBY,指示即將進入待機模式Delay_ms(1000);OLED_ShowString(4, 9, " ");Delay_ms(100);OLED_Clear();//OLED清屏,模擬關閉外部所有的耗電設備,以達到極度省電//STM32進入待機模式之前,要把外部接入的模塊能停的都停掉,能斷電的都斷掉,以最大化的省電PWR_EnterSTANDBYMode();//程序從頭開始執行//注意:復位+下載+松手}
}