開發環境:
MDK:Keil 5.30
開發板:GD32F207I-EVAL
MCU:GD32F207IK
1 GD32電源管理
GD32的工作電壓(VDD)為2.0~3.6V。通過內置的電壓調節器提供所需的1.8V電源。當主電源VDD掉電后,通過VBAT腳為實時時鐘(RTC)和備份寄存器提供電源。
使用電池或其他電源連接到VBAT腳上,當VDD斷電時,可以保存備份寄存器的內容和維持RTC的功能。
VBAT腳為RTC、 LSE振蕩器和PC13至PC15端口供電,可以保證當主電源被切斷時RTC能繼續工作。切換到VBAT供電的開關,由復位模塊中的掉電復位功能控制。
當備份域由VDD供電(VBAK連接至VDD)時,以下功能可用:
● PC13可以作為通用I/O口或RTC功能引腳;
● PC14和PC15可以作為通用I/O口或LXTAL晶振引腳。
● PI8可以作為通用I/O口或RTC功能引腳
當備份域由VBAT電源供電時(VBAK連接至VBAT),以下功能可用:
● PC13僅可以作為RTC功能引腳;
● PC14和PC15僅可作為LXTAL晶振引腳。
● PI8僅可以作為RTC功能引腳
注意:由于PC13至PC15引腳是通過電源切換器供電的,電源切換器僅可通過小電流,因此當PC13至PC15的GPIO口在輸出模式時,其工作的速度不能超過2MHz(最大負載為30pF)。
2 GD32低功耗模式
在系統或電源復位以后,微控制器處于運行狀態。當CPU不需繼續運行時,可以利用多種低功耗模式來節省功耗,例如等待某個外部事件時。用戶需要根據最低電源消耗、最快速啟動時間和可用的喚醒源等條件,選定一個最佳的低功耗模式。
GD32F207有三種低功耗模式:
● 深度睡眠/停止模式(所有的時鐘都已停止)
● 待機模式(1.8V電源關閉)
此外,在運行模式下,可以通過以下方式中的一種降低功耗:
● 降低系統時鐘
● 關閉APB和AHB總線上未被使用的外設時鐘。
從表中可以看到,這三種低功耗模式層層遞進,運行的時鐘或芯片功能越來越少,因而功耗越來越低。
在睡眠模式中,僅關閉了 CPU 時鐘, CPU 停止運行 ,但其片上外設,CM3 核心外設全都還照常運行。有兩種方式進入睡眠模式,它的進入方式決定了從睡眠喚醒的方式,分別是 WFI(wait for interrupt)和 WFE(wait for event),即由等待“中斷”喚醒和由“事件”喚醒。
在深度睡眠模式中, 進一步關閉了其它所有的時鐘 ,于是所有的外設都停止了工作,但由于其 1.8V 區域的電源沒有關閉,還保留了 CPU 的寄存器、內存的信息,所以深度睡眠模式喚醒,并重新開啟時鐘后,還可以從上次深度睡眠處繼續執行代碼。深度睡眠模式可以由任意一個外部中斷(EXTI)喚醒。在深度睡眠模式中可以選擇電壓調節器為開模式或低功耗模式,若選擇低功耗模式,在喚醒時會加上電壓調節器的喚醒延遲。
待機模式,這與我們平時印象中的手機關機模式相似,它除了關閉所有的時鐘,還把1.8V 區域的電源也關閉了,也就是說,從待機模式喚醒后,由于沒有之前代碼的運行記錄,只能對芯片復位,重新檢測 boot 條件,從頭開始執行程序。它有四種喚醒方式,分別是 WKUP(PA0)引腳的上升沿,RTC 鬧鐘事件,NRST 引腳的復位和FWDGT復位。
在運行模式下,任何時候都可以通過停止為外設和內存提供時鐘來減少功耗。為了在睡眠模式下更多地減少功耗,可在執行WFI或WFE指令前關閉所有外設的時鐘。
通過設置AHB外設時鐘使能寄存器、APB2外設時鐘使能寄存器和APB1外設時鐘使能寄存器來開關各個外設模塊的時鐘。
2.1睡眠模式
- 進入睡眠模式
通過執行WFI或WFE指令進入睡眠狀態。根據Cortex?-M3中SCR(系統控制寄存器)的SLEEPONEXIT位,有兩種睡眠進入機制選項:
● Sleep-now:如果SLEEPONEXIT位被清零,一旦執行WFI或WFE指令, MCU立即進入睡眠模式;
● Sleep-on-exit:如果SLEEPONEXIT位被置位,當系統從最低優先級的中斷處理程序離開后, MCU立即進入睡眠模式。
在睡眠模式下,所有的I/O引腳都保持它們在運行模式時的狀態。
- 退出睡眠模式
如果執行WFI指令進入睡眠模式,任意一個被嵌套向量中斷控制器響應的外設中斷都能將系統從睡眠模式喚醒。
如果執行WFE指令進入睡眠模式,則一旦發生喚醒事件時,微處理器都將從睡眠模式退出。喚醒事件可以通過下述方式產生:
● 在外設控制寄存器中使能一個中斷,而不是在NVIC(嵌套向量中斷控制器)中使能,并且在Cortex-M3系統控制寄存器中使能SEVONPEND位。當MCU從WFE中喚醒后,外設的中斷掛起位和外設的NVIC中斷通道掛起位(在NVIC中斷清除掛起寄存器中)必須被清除。
● 配置一個外部或內部的EXIT線為事件模式。當MCU從WFE中喚醒后,因為與事件線對應的掛起位未被設置,不必清除外設的中斷掛起位或外設的NVIC中斷通道掛起位。
該模式喚醒所需的時間最短,因為沒有時間損失在中斷的進入或退出上。
SLEEP-NOW****模式 | 說明 |
---|---|
進入 | 在以下條件下執行WFI(等待中斷)或WFE(等待事件)指令: –SLEEPDEEP = 0和–SLEEPONEXIT = 0參考Cortex-M3系統控制寄存器。 |
退出 | 如果執行WFI進入睡眠模式:中斷。 如果執行WFE進入睡眠模式:喚醒事件。 |
喚醒延時 | 無 |
SLEEP-ON_EXIT****模式 | 說明 |
---|---|
進入 | 在以下條件下執行WFI指令:–SLEEPDEEP = 0和–SLEEPONEXIT = 1參考Cortex?-M3系統控制寄存器 |
退出 | 中斷:參考中斷向量表 |
喚醒延時 | 無 |
2.2 深度睡眠模式
深度睡眠模式是在Cortex?-M3的深睡眠模式基礎上結合了外設的時鐘控制機制,深度睡眠模式與 Cortex?-M3 的 SLEEPDEEP 模式相對應。在深度睡眠模式下,1.2V 域中的所有時鐘全部關閉,IRC8M、HXTAL及PLLs 也全部被禁用。SRAM和寄存器中的內容被保留。
在停止模式下,所有的I/O引腳都保持它們在運行模式時的狀態。
- 進入深度睡眠模式
在深度睡眠模式下,通過設置電源控制寄存器PMU_CTL的LDOLP位使內部調節器進入低功耗模式,能夠降低更多的功耗。
如果正在進行閃存編程,直到對內存訪問完成,系統才進入深度睡眠模式。
如果正在進行對APB的訪問,直到對APB訪問完成,系統才進入深度睡眠模式。可以通過對獨立的控制位進行編程。
在深度睡眠模式下,如果在進入該模式前ADC和DAC沒有被關閉,那么這些外設仍然消耗電流。
- 退出深度睡眠模式
當一個中斷或喚醒事件導致退出深度睡眠模式時,IRC8M、IRC40K振蕩器被選為系統時鐘。
當電壓調節器處于低功耗模式下,當系統從深度睡眠模式退出時,將會有一段額外的啟動延時。如果在深度睡眠模式期間保持內部調節器開啟,則退出啟動時間會縮短,但相應的功耗會增加。
深度睡眠模式 | 說明 |
---|---|
進入 | 在以下條件下執行WFI(等待中斷)或WFE(等待事件)指令: –設置Cortex-M3系統控制寄存器中的SLEEPDEEP位 –清除電源控制寄存器(PMU_CTL)中的STBMOD位 –通過設置PMU_CTL中LDOLP位選擇電壓調節器的模式 注:為了進入停止模式,所有的外部中斷的請求位(掛起寄存器)和RTC的鬧鐘標志都必須被清除,否則停止模式的進入流程將會被跳過,程序繼續運行。 |
退出 | 如果執行WFI進入停止模式: 設置任一外部中斷線為中斷模式(在NVIC中必須使能相應的外部中斷向量)。參見中斷向量。 如果執行WFE進入停止模式: 設置任一外部中斷線為事件模式。參見喚醒事件管理。 |
喚醒延時 | IRC8M、IRC40K喚醒時間+電壓調節器從低功耗喚醒的時間。 |
2.3待機模式
待機模式可實現系統的最低功耗。該模式是在Cortex-M3深睡眠模式時關閉電壓調節器。整個1.8V供電區域被斷電。IRC8M、HXTAL 和 PLL振蕩器也被斷電。SRAM和寄存器內容丟失。只有備份的寄存器和待機電路維持供電。
- 進入待機模式
進入待機模式前,先將Cortex?-M3 系統控制寄存器的 SLEEPDEEP 位置 1,再將 PMU_CTL 寄存器的 STBMOD 位置 1,再清除 PMU_CS 寄存器的 WUF 位,然后執行 WFI 或 WFE 指令,系統進入待機模式,PMU_CS 寄存器的 STBF 位狀態表示 MCU 是否已進入待機模式。
- 退出待機模式
當一個外部復位(NRST引腳)、 FWDGT復位、 WKUP引腳上的上升沿或RTC鬧鐘事件的上升沿發生時,微控制器從待機模式退出。從待機喚醒后,除了電源控制/狀態寄存器(PWR_CS),所有寄存器被復位。
從待機模式喚醒后的代碼執行等同于復位后的執行(采樣啟動模式引腳、讀取復位向量等)。 電源控制/狀態寄存器(PWR_CS)將會指示內核由待機狀態退出。
待機模式可實現系統的最低功耗。該模式是在Cortex-M3深睡眠模式時關閉電壓調節器。整個1.8V供電區域被斷電。IRC8M、HXTAL 和 PLL振蕩器也被斷電。SRAM和寄存器內容丟失。只有備份的寄存器和待機電路維持供電。
待機模式 | 說明 |
---|---|
進入 | 在以下條件下執行WFI(等待中斷)或WFE(等待事件)指令: –設置Cortex?-M3系統控制寄存器中的SLEEPDEEP位 –設置電源控制寄存器(PWR_CTL)中的STBMOD位 –清除電源控制/狀態寄存器(PWR_CS)中的WUF位 |
退出 | WKUP引腳的上升沿、RTC鬧鐘事件的上升沿、NRST引腳上外部復位、FWDGT復位。 |
喚醒延時 | 復位階段時電壓調節器的啟動 |
3 低功耗的寄存器描述
電源控制寄存器(PWR_CTL),該寄存器的各位描述如下圖所示:
我們通過設置 PWR_CTL的 STBMOD位,使 CPU 進入深度睡眠時進入待機模式。
電源控制/狀態寄存器( PWR_CS)的各位描述如圖所示。
通過設置 PWR_CS的 WUPEN 位,來使能 WKUP 引腳用于待機模式喚醒。我們還可以從 WUF 來檢查是否發生了喚醒事件。
4 低功耗具體代碼實現
通過以上介紹,我們了解了進入低功耗模式的三種方法,在者三種模式中待機模式功耗最低。筆者這里使用的是按鍵喚醒,其電路如下:
4.1睡眠模式
睡眠模式很簡單,就是通過以下指令進入睡眠:
__WFI();
__WFE();
那么以上兩條指令又是啥意思呢?WFI(Wait for interrupt)和WFE(Wait for event)是兩個讓ARM核進入low-power standby模式的指令,由ARM architecture定義,由ARM core實現。我們可以在core_cmx3.h(筆者使用的是GD32F207,對應的就是core_cmx3.h,其他內核類似),中找到以上指令的定義。
static __INLINE void __WFI() { __ASM volatile ("wfi"); }
static __INLINE void __WFE() { __ASM volatile ("wfe"); }
以上就是把匯編指令都封裝成了諸如__Commnad()的函數形式,并且預編譯為二進制包。那么以上指令都能讓ARM進入睡眠模式,又有啥區別呢?
對WFI來說,執行WFI指令后,ARM core會立即進入low-power standby state,直到有WFI Wakeup events發生。
而WFE則稍微不同,執行WFE指令后,根據Event Register(一個單bit的寄存器,每個PE一個)的狀態,有兩種情況:如果Event Register為1,該指令會把它清零,然后執行完成(不會standby);如果Event Register為0,和WFI類似,進入low-power standby state,直到有WFE Wakeup events發生。
總結一下,這兩條指令的作用都是令MCU進入休眠/待機狀態以便降低功耗,但是略有區別:
WFI: wait for Interrupt 等待中斷,即下一次中斷發生前都在此hold住不干活
WFE: wait for Events 等待事件,即下一次事件發生前都在此hold住不干活
因此我們要項喚醒MCU,最簡單的就是通過中斷喚醒。
睡眠模式時通過按鍵中斷喚醒,代碼如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//usart init 115200 8-N-1
com_init(COM1, USART_MODE_GPIO, 115200, 0, 1);
/* configure LED1 GPIO port */
led_init(LED1);
/* configure LED2 GPIO port */
led_init(LED2);
/* configure LED3 GPIO port */
led_init(LED3);
/* configure LED4 GPIO port */
led_init(LED4);
//key init
key_init(KEY_WAKEUP, KEY_MODE_EXTI);
printf("\\r\\n Sleep Test \\r\\n");
while(1)
{
led_toggle(LED1);
Delay(0xFFFFF);
led_toggle(LED2);
Delay(0xFFFFF);
led_toggle(LED3);
Delay(0xFFFFF);
led_toggle(LED4);
//__WFI(); //進入睡眠模式,等待中斷喚醒 方式一
__WFE(); //方式二
}
}
進入睡眠模式也可調用庫函數。
void pmu_to_sleepmode(uint8_t sleepmodecmd)
值得注意的是,這里不能用滴答定時器來延時,因為這里使用的是中斷方式實現的。
WFI和WFE兩條指令讓MCU進入睡眠模式,均可通過按鍵中斷喚醒,但是他們的喚醒本質是有區別的。
如上圖所示,圖中的藍色虛線箭頭標出了中斷信號的傳輸路徑,而紅色箭頭標出了事件的傳輸路徑。雖然中斷和事件的產生源都是一樣的,都是通過按鍵產生,但是路徑卻有不同,中斷是需要CPU參與的,需要軟件的中斷服務函數才能完成中斷后產生的結果;事件是靠脈沖發生器產生一個脈沖,進而由硬件自動完成這個事件產生的結果,當然相應的聯動部件需要先設置好,比如引起DMA操作,AD轉換等。
4.2 深度睡眠模式
進入深度睡眠模式之后,任何外部中斷都可以喚醒低功耗,但是需要重新配置時鐘,不然系統將以默認時鐘(沒有經過倍頻)運行。筆者這里還是使用外部中斷喚醒。我們先看看主函數。
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//usart init 115200 8-N-1
com_init(COM1, USART_MODE_GPIO, 115200, 0, 1);
/* configure LED1 GPIO port */
led_init(LED1);
/* configure LED2 GPIO port */
led_init(LED2);
/* configure LED3 GPIO port */
led_init(LED3);
/* configure LED4 GPIO port */
led_init(LED4);
//key init
key_init(KEY_WAKEUP, KEY_MODE_EXTI);
/* 使能電源管理單元的時鐘 */
rcu_periph_clock_enable(RCU_PMU);
printf("\\r\\n Enter stop mode \\r\\n");
/* 進入深度睡眠模式,設置電壓調節器為低功耗模式,等待中斷喚醒*/
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER,WFI_CMD);
while(1)
{
led_toggle(LED1);
Delay(0xFFFFF);
led_toggle(LED2);
Delay(0xFFFFF);
led_toggle(LED3);
Delay(0xFFFFF);
led_toggle(LED4);
}
}
以上最重要的就一句:
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER,WFI_CMD);
這是MCU進入低功耗模式的庫函數,在gd32f20x_pmu.c中實現,原型如下:
/*!
\\brief PMU work in deepsleep mode
\\param[in] ldo:
only one parameter can be selected which is shown as below:
\\arg PMU_LDO_NORMAL: LDO work at normal power mode when pmu enter deepsleep mode
\\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
\\param[in] deepsleepmodecmd:
only one parameter can be selected which is shown as below:
\\arg WFI_CMD: use WFI command
\\arg WFE_CMD: use WFE command
\\param[out] none
\\retval none
*/
void pmu_to_deepsleepmode(uint32_t ldo, uint8_t deepsleepmodecmd)
{
static uint32_t reg_snap[4];
/* clear stbmod and ldolp bits */
PMU_CTL &= ~((uint32_t)(PMU_CTL_STBMOD | PMU_CTL_LDOLP));
/* set ldolp bit according to pmu_ldo */
PMU_CTL |= ldo;
/* set sleepdeep bit of Cortex-M3 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
reg_snap[0] = REG32(0xE000E010U);
reg_snap[1] = REG32(0xE000E100U);
reg_snap[2] = REG32(0xE000E104U);
reg_snap[3] = REG32(0xE000E108U);
REG32(0xE000E010U) &= 0x00010004U;
REG32(0xE000E180U) = 0XFF7FF83DU;
REG32(0xE000E184U) = 0XBFFFF8FFU;
REG32(0xE000E188U) = 0xFFFFFFFFU;
/* select WFI or WFE command to enter deepsleep mode */
if(WFI_CMD == deepsleepmodecmd) {
__WFI();
} else {
__SEV();
__WFE();
__WFE();
}
REG32(0xE000E010U) = reg_snap[0] ;
REG32(0xE000E100U) = reg_snap[1] ;
REG32(0xE000E104U) = reg_snap[2] ;
REG32(0xE000E108U) = reg_snap[3] ;
/* reset sleepdeep bit of Cortex-M3 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
上述函數主要節做了四件事:
1.設置Cortex-M3系統控制寄存器中的SLEEPDEEP位(SCB_SCR參考Cortex-M3權威指南182頁)。
2.清除電源控制寄存器(PWR_CTL)中的STBMOD位。
3.通過設置PWR_CR中LDOLP位選擇電壓調節器的模式。
4.執行WFI或者WFE匯編指令。
我們可以選擇事件和中斷喚醒兩種方式,選擇哪種方式是根據庫函數的第二個參數決定的,筆者這里使用的中斷喚醒。
深度睡眠模式下MCU喚醒之后,時鐘和頻率是沒有經過倍頻的,在GD32F207上,低功耗喚醒之后,是8M頻率運行,而正常運行是120M。所以,在喚醒停機模式之后,需要重新配置時鐘。最簡單就是直接調用庫函數:
SystemInit();
當然也可以自己重寫時鐘初始化函數。
好了,我們最后再看看中斷喚醒的函數:
/*!
\\brief this function handles external lines 0 interrupt request
\\param[in] none
\\param[out] none
\\retval none
*/
void EXTI0_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_0))
{
printf("\\r\\n Enter interrupt \\r\\n");
SystemInit();
printf("\\r\\n Quit interrupt \\r\\n");
exti_interrupt_flag_clear(EXTI_0);
}
}
進入中斷后主要是重啟時鐘,然后就會接著運行程序。
4.3 待機模式
待機模式的功耗最低。待機模式的具體步驟如下:
1) 使能電源時鐘。
因為要配置電源控制寄存器,所以必須先使能電源時鐘。在庫函數中,使能電源時鐘的方法是:
rcu_periph_clock_enable(RCU_PMU); //使能 PWR 外設時鐘
- 設置 WK_UP 引腳作為喚醒源。
使能時鐘之后再設置 PWR_CS 的WUPEN位,使能WUPEN用于將 CPU 從待機模式喚醒。在庫函數中,設置使能WUPEN用于喚醒 CPU 待機模式的函數是:
pmu_wakeup_pin_enable (); //使能喚醒管腳功能
3) 設置 SLEEPDEEP 位,設置 STBMOD位,執行 WFI 指令,進入待機模式。
進入待機模式, 首先要設置 SLEEPDEEP 位( 該位在系統控制寄存器( SCB_SCR)的第二位,詳見《 CM3 權威指南》), 接著我們通過 PWR_CTL設置 STBMOD位,使得 CPU 進入深度睡眠時進入待機模式,最后執行 WFI 指令開始進入待機模式,并等待 WK_UP中斷的到來。在庫函數中,進行上面三個功能進入待機模式是在函數pmu_to_standbymode中實現的:
void pmu_to_standbymode(uint8_t standbymodecmd);
pmu_to_standbymode ()函數原型如下所示:
/*!
\\brief pmu work in standby mode
\\param[in] standbymodecmd:
only one parameter can be selected which is shown as below:
\\arg WFI_CMD: use WFI command
\\arg WFE_CMD: use WFE command
\\param[out] none
\\retval none
*/
void pmu_to_standbymode(uint8_t standbymodecmd)
{
/* set sleepdeep bit of Cortex-M3 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* set stbmod bit */
PMU_CTL |= PMU_CTL_STBMOD;
/* reset wakeup flag */
PMU_CTL |= PMU_CTL_WURST;
/* select WFI or WFE command to enter standby mode */
if(WFI_CMD == standbymodecmd) {
__WFI();
} else {
__WFE();
}
}
該函數中先配置了STBMOD寄存器位及 SLEEPDEEP 寄存器位,接著調用__force_stores函數確保存儲操作完畢后再調用 WFI 指令,從而進入待機模式。這里值得注意的是,待機模式也可以使用 WFE 指令進入的。
在進入待機模式后,除了被使能了的用于喚醒的 I/O,其余 I/O 都進入高阻態,而待機模式喚醒后,相當于復位 GD32 芯片,程序重新從頭開始執行。
4) 最后編寫 WK_UP 中斷/事件函數。
因為我們通過 WK_UP 中斷/事件( PA0 中斷/事件)來喚醒MCU,所以我們有必要設置一下該中斷函數,同時我們也通過該函數里面進入待機模式。
/**
* @brief 用于檢測按鍵是否被長時間按下
* @param 無
* @retval 1 :按鍵被長時間按下 0 :按鍵沒有被長時間按下
*/
uint8_t pwr_check_standby(void)
{
uint8_t downCnt = 0; //記錄按下的次數
uint8_t upCnt = 0; //記錄松開的次數
while(1) //死循環,由return結束
{
if(RESET == gpio_input_bit_get(GPIOA, GPIO_PIN_0))//檢測到按下按鍵
{
led_on(LED1);led_on(LED2);led_on(LED3);led_on(LED4); //點亮所有LED燈
downCnt++; //記錄按下次數
upCnt=0; //清除按鍵釋放記錄
Delay(0xFFFF);
if(downCnt>=100) //按下時間足夠
{
led_off(LED1);led_off(LED2);led_off(LED3);led_off(LED4);
return 1; //檢測到按鍵被時間長按下
}
}
else
{
upCnt++; //記錄釋放次數
if(upCnt>5) //連續檢測到釋放超過5次
{
led_off(LED1);led_off(LED2);led_off(LED3);led_off(LED4); //關閉所有LED燈
return 0; //按下時間太短,不是按鍵長按操作
}
}
}
}
通過以上幾個步驟的設置,我們就可以使用 GD32 的待機模式了,并且可以通過 WK_UP來喚醒 MCU。
主函數如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//usart init 115200 8-N-1
com_init(COM1, USART_MODE_GPIO, 115200, 0, 1);
/* configure LED1 GPIO port */
led_init(LED1);
/* configure LED2 GPIO port */
led_init(LED2);
/* configure LED3 GPIO port */
led_init(LED3);
/* configure LED4 GPIO port */
led_init(LED4);
//key init
key_init(KEY_WAKEUP, KEY_MODE_GPIO);
/* 使能電源管理單元的時鐘 */
rcu_periph_clock_enable(RCU_PMU);
if(pmu_flag_get(PMU_FLAG_WAKEUP) == SET)
{
printf("\\r\\n Standby wake-up reset \\r\\n");
}
else
{
printf("\\r\\n Power-on reset\\r\\n");
}
while(1)
{
led_toggle(LED1);
Delay(0xFFFFF);
led_toggle(LED2);
Delay(0xFFFFF);
led_toggle(LED3);
Delay(0xFFFFF);
led_toggle(LED4);
if(pwr_check_standby())
{
printf("\\r\\n Enter standby mode\\r\\n");
/*清除 WU 狀態位*/
pmu_flag_clear (PMU_FLAG_RESET_WAKEUP);
/* 使能WKUP引腳的喚醒功能 */
pmu_wakeup_pin_enable ();
/* 進入待機模式,等待喚醒*/
pmu_to_standbymode(WFI_CMD);
}
}
}
在循環體外使用庫函數 pmu_flag_get檢測 PMU_FLAG_WAKEUP標志位,當這個標志位為SET 狀態的時候,表示本次系統是從待機模式喚醒的復位,否則可能是上電復位。其中PMU_FLAG_WAKEUP的標志位在gd32f20x_pmu.h中定義。
pwr_check_standby()函數用于檢測漸漸是否長按,當長按后就進入待機模式。
5 低功耗實驗現象
5.1睡眠模式
將程序編譯好后下載到板子上,可以看到4個LED依次閃爍,然后熄滅。按下KEY1按鍵,3個LED再次依次閃爍。
圖6
5.2 深度睡眠模式
將程序編譯好后下載到板子上。按下KEY1按鍵,4個LED依次閃爍。串口依次打印信息如下:
當程序運行后會首先深度睡眠模式,當按鍵按下后,退出深度睡眠模式,則程序又會繼續運行。
5.3待機模式
將程序編譯好后下載到板子上。按下按鍵,4個LED依次閃爍。長按KEY1按鍵,MCU進入待機模式,LED熄滅,再次按下KEY1按鍵,LED會同時點亮,直到同時熄滅,松開KEY1按鍵,KEY1按下會使 PA0 引腳產生一個上升沿,從而喚醒系統。
系統喚醒后會進行復位,從頭開始執行上述過程,與第一次上電時不同的是,這樣的復位會使 PWR_FLAG_WU 標志位改為 SET 狀態,LED再次依次閃爍。串口打印信息如下。
-
mcu
+關注
關注
146文章
17123瀏覽量
350983 -
電源管理
+關注
關注
115文章
6177瀏覽量
144443 -
低功耗
+關注
關注
10文章
2396瀏覽量
103670 -
開發板
+關注
關注
25文章
5032瀏覽量
97371 -
GD32
+關注
關注
7文章
403瀏覽量
24328
發布評論請先 登錄
相關推薦
評論