0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)篇) 第15章 低功耗

嵌入式大雜燴 ? 來源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2023-05-17 08:59 ? 次閱讀

開發(fā)環(huán)境:

MDK:Keil 5.30

開發(fā)板:GD32F207I-EVAL

MCU:GD32F207IK

1 GD32電源管理

GD32的工作電壓(VDD)為2.0~3.6V。通過內(nèi)置的電壓調(diào)節(jié)器提供所需的1.8V電源。當(dāng)主電源VDD掉電后,通過VBAT腳為實時時鐘(RTC)和備份寄存器供電源。

1684245485489k9nyiyuks9

使用電池或其他電源連接到VBAT腳上,當(dāng)VDD斷電時,可以保存?zhèn)浞菁拇嫫鞯膬?nèi)容和維持RTC的功能。

VBAT腳為RTC、 LSE振蕩器和PC13至PC15端口供電,可以保證當(dāng)主電源被切斷時RTC能繼續(xù)工作。切換到VBAT供電的開關(guān),由復(fù)位模塊中的掉電復(fù)位功能控制。

當(dāng)備份域由VDD供電(VBAK連接至VDD)時,以下功能可用:

● PC13可以作為通用I/O口或RTC功能引腳;

● PC14和PC15可以作為通用I/O口或LXTAL晶振引腳。

PI8可以作為通用I/O口或RTC功能引腳

當(dāng)備份域由VBAT電源供電時(VBAK連接至VBAT),以下功能可用:

● PC13僅可以作為RTC功能引腳;

● PC14和PC15僅可作為LXTAL晶振引腳。

● PI8僅可以作為RTC功能引腳

注意:由于PC13至PC15引腳是通過電源切換器供電的,電源切換器僅可通過小電流,因此當(dāng)PC13至PC15的GPIO口在輸出模式時,其工作的速度不能超過2MHz(最大負(fù)載為30pF)。

2 GD32低功耗模式

在系統(tǒng)或電源復(fù)位以后,微控制器處于運(yùn)行狀態(tài)。當(dāng)CPU不需繼續(xù)運(yùn)行時,可以利用多種低功耗模式來節(jié)省功耗,例如等待某個外部事件時。用戶需要根據(jù)最低電源消耗、最快速啟動時間和可用的喚醒源等條件,選定一個最佳的低功耗模式。

GD32F207有三種低功耗模式:

  • 睡眠模式(Cortex?-M3內(nèi)核停止,所有外設(shè)包括Cortex-M3核心的外設(shè),如NVIC、系統(tǒng)時鐘(SysTick)等仍在運(yùn)行)

● 深度睡眠/停止模式(所有的時鐘都已停止)

● 待機(jī)模式(1.8V電源關(guān)閉)

此外,在運(yùn)行模式下,可以通過以下方式中的一種降低功耗:

● 降低系統(tǒng)時鐘

● 關(guān)閉APB和AHB總線上未被使用的外設(shè)時鐘。

1684245486046vja3pvlwnn

從表中可以看到,這三種低功耗模式層層遞進(jìn),運(yùn)行的時鐘或芯片功能越來越少,因而功耗越來越低。

在睡眠模式中,僅關(guān)閉了 CPU 時鐘, CPU 停止運(yùn)行 ,但其片上外設(shè),CM3 核心外設(shè)全都還照常運(yùn)行。有兩種方式進(jìn)入睡眠模式,它的進(jìn)入方式?jīng)Q定了從睡眠喚醒的方式,分別是 WFI(wait for interrupt)和 WFE(wait for event),即由等待“中斷”喚醒和由“事件”喚醒。

在深度睡眠模式中, 進(jìn)一步關(guān)閉了其它所有的時鐘 ,于是所有的外設(shè)都停止了工作,但由于其 1.8V 區(qū)域的電源沒有關(guān)閉,還保留了 CPU 的寄存器、內(nèi)存的信息,所以深度睡眠模式喚醒,并重新開啟時鐘后,還可以從上次深度睡眠處繼續(xù)執(zhí)行代碼。深度睡眠模式可以由任意一個外部中斷(EXTI)喚醒。在深度睡眠模式中可以選擇電壓調(diào)節(jié)器為開模式或低功耗模式,若選擇低功耗模式,在喚醒時會加上電壓調(diào)節(jié)器的喚醒延遲。

待機(jī)模式,這與我們平時印象中的手機(jī)關(guān)機(jī)模式相似,它除了關(guān)閉所有的時鐘,還把1.8V 區(qū)域的電源也關(guān)閉了,也就是說,從待機(jī)模式喚醒后,由于沒有之前代碼的運(yùn)行記錄,只能對芯片復(fù)位,重新檢測 boot 條件,從頭開始執(zhí)行程序。它有四種喚醒方式,分別是 WKUP(PA0)引腳的上升沿,RTC 鬧鐘事件,NRST 引腳的復(fù)位和FWDGT復(fù)位。

在運(yùn)行模式下,任何時候都可以通過停止為外設(shè)和內(nèi)存提供時鐘來減少功耗。為了在睡眠模式下更多地減少功耗,可在執(zhí)行WFI或WFE指令前關(guān)閉所有外設(shè)的時鐘。

通過設(shè)置AHB外設(shè)時鐘使能寄存器、APB2外設(shè)時鐘使能寄存器和APB1外設(shè)時鐘使能寄存器來開關(guān)各個外設(shè)模塊的時鐘。

2.1睡眠模式

  • 進(jìn)入睡眠模式

通過執(zhí)行WFI或WFE指令進(jìn)入睡眠狀態(tài)。根據(jù)Cortex?-M3中SCR(系統(tǒng)控制寄存器)的SLEEPONEXIT位,有兩種睡眠進(jìn)入機(jī)制選項:

● Sleep-now:如果SLEEPONEXIT位被清零,一旦執(zhí)行WFI或WFE指令, MCU立即進(jìn)入睡眠模式;

● Sleep-on-exit:如果SLEEPONEXIT位被置位,當(dāng)系統(tǒng)從最低優(yōu)先級的中斷處理程序離開后, MCU立即進(jìn)入睡眠模式。

在睡眠模式下,所有的I/O引腳都保持它們在運(yùn)行模式時的狀態(tài)。

  • 退出睡眠模式

如果執(zhí)行WFI指令進(jìn)入睡眠模式,任意一個被嵌套向量中斷控制器響應(yīng)的外設(shè)中斷都能將系統(tǒng)從睡眠模式喚醒。

如果執(zhí)行WFE指令進(jìn)入睡眠模式,則一旦發(fā)生喚醒事件時,微處理器都將從睡眠模式退出。喚醒事件可以通過下述方式產(chǎn)生:

● 在外設(shè)控制寄存器中使能一個中斷,而不是在NVIC(嵌套向量中斷控制器)中使能,并且在Cortex-M3系統(tǒng)控制寄存器中使能SEVONPEND位。當(dāng)MCU從WFE中喚醒后,外設(shè)的中斷掛起位和外設(shè)的NVIC中斷通道掛起位(在NVIC中斷清除掛起寄存器中)必須被清除。

● 配置一個外部或內(nèi)部的EXIT線為事件模式。當(dāng)MCU從WFE中喚醒后,因為與事件線對應(yīng)的掛起位未被設(shè)置,不必清除外設(shè)的中斷掛起位或外設(shè)的NVIC中斷通道掛起位。

該模式喚醒所需的時間最短,因為沒有時間損失在中斷的進(jìn)入或退出上。

SLEEP-NOW****模式 說明
進(jìn)入 在以下條件下執(zhí)行WFI(等待中斷)或WFE(等待事件)指令: –SLEEPDEEP = 0和–SLEEPONEXIT = 0參考Cortex-M3系統(tǒng)控制寄存器。
退出 如果執(zhí)行WFI進(jìn)入睡眠模式:中斷。 如果執(zhí)行WFE進(jìn)入睡眠模式:喚醒事件。
喚醒延時
SLEEP-ON_EXIT****模式 說明
進(jìn)入 在以下條件下執(zhí)行WFI指令:–SLEEPDEEP = 0和–SLEEPONEXIT = 1參考Cortex?-M3系統(tǒng)控制寄存器
退出 中斷:參考中斷向量表
喚醒延時

2.2 深度睡眠模式

深度睡眠模式是在Cortex?-M3的深睡眠模式基礎(chǔ)上結(jié)合了外設(shè)的時鐘控制機(jī)制,深度睡眠模式與 Cortex?-M3 的 SLEEPDEEP 模式相對應(yīng)。在深度睡眠模式下,1.2V 域中的所有時鐘全部關(guān)閉,IRC8M、HXTAL及PLLs 也全部被禁用。SRAM和寄存器中的內(nèi)容被保留。

在停止模式下,所有的I/O引腳都保持它們在運(yùn)行模式時的狀態(tài)。

  • 進(jìn)入深度睡眠模式

在深度睡眠模式下,通過設(shè)置電源控制寄存器PMU_CTL的LDOLP位使內(nèi)部調(diào)節(jié)器進(jìn)入低功耗模式,能夠降低更多的功耗。

如果正在進(jìn)行閃存編程,直到對內(nèi)存訪問完成,系統(tǒng)才進(jìn)入深度睡眠模式。

如果正在進(jìn)行對APB的訪問,直到對APB訪問完成,系統(tǒng)才進(jìn)入深度睡眠模式??梢酝ㄟ^對獨(dú)立的控制位進(jìn)行編程。

在深度睡眠模式下,如果在進(jìn)入該模式前ADCDAC沒有被關(guān)閉,那么這些外設(shè)仍然消耗電流。

  • 退出深度睡眠模式

當(dāng)一個中斷或喚醒事件導(dǎo)致退出深度睡眠模式時,IRC8M、IRC40K振蕩器被選為系統(tǒng)時鐘。

當(dāng)電壓調(diào)節(jié)器處于低功耗模式下,當(dāng)系統(tǒng)從深度睡眠模式退出時,將會有一段額外的啟動延時。如果在深度睡眠模式期間保持內(nèi)部調(diào)節(jié)器開啟,則退出啟動時間會縮短,但相應(yīng)的功耗會增加。

深度睡眠模式 說明
進(jìn)入 在以下條件下執(zhí)行WFI(等待中斷)或WFE(等待事件)指令: –設(shè)置Cortex-M3系統(tǒng)控制寄存器中的SLEEPDEEP位 –清除電源控制寄存器(PMU_CTL)中的STBMOD位 –通過設(shè)置PMU_CTL中LDOLP位選擇電壓調(diào)節(jié)器的模式 注:為了進(jìn)入停止模式,所有的外部中斷的請求位(掛起寄存器)和RTC的鬧鐘標(biāo)志都必須被清除,否則停止模式的進(jìn)入流程將會被跳過,程序繼續(xù)運(yùn)行。
退出 如果執(zhí)行WFI進(jìn)入停止模式: 設(shè)置任一外部中斷線為中斷模式(在NVIC中必須使能相應(yīng)的外部中斷向量)。參見中斷向量。 如果執(zhí)行WFE進(jìn)入停止模式: 設(shè)置任一外部中斷線為事件模式。參見喚醒事件管理。
喚醒延時 IRC8M、IRC40K喚醒時間+電壓調(diào)節(jié)器從低功耗喚醒的時間。

2.3待機(jī)模式

待機(jī)模式可實現(xiàn)系統(tǒng)的最低功耗。該模式是在Cortex-M3深睡眠模式時關(guān)閉電壓調(diào)節(jié)器。整個1.8V供電區(qū)域被斷電。IRC8M、HXTAL 和 PLL振蕩器也被斷電。SRAM和寄存器內(nèi)容丟失。只有備份的寄存器和待機(jī)電路維持供電。

  • 進(jìn)入待機(jī)模式

進(jìn)入待機(jī)模式前,先將Cortex?-M3 系統(tǒng)控制寄存器的 SLEEPDEEP 位置 1,再將 PMU_CTL 寄存器的 STBMOD 位置 1,再清除 PMU_CS 寄存器的 WUF 位,然后執(zhí)行 WFI 或 WFE 指令,系統(tǒng)進(jìn)入待機(jī)模式,PMU_CS 寄存器的 STBF 位狀態(tài)表示 MCU 是否已進(jìn)入待機(jī)模式。

  • 退出待機(jī)模式

當(dāng)一個外部復(fù)位(NRST引腳)、 FWDGT復(fù)位、 WKUP引腳上的上升沿或RTC鬧鐘事件的上升沿發(fā)生時,微控制器從待機(jī)模式退出。從待機(jī)喚醒后,除了電源控制/狀態(tài)寄存器(PWR_CS),所有寄存器被復(fù)位。

從待機(jī)模式喚醒后的代碼執(zhí)行等同于復(fù)位后的執(zhí)行(采樣啟動模式引腳、讀取復(fù)位向量等)。 電源控制/狀態(tài)寄存器(PWR_CS)將會指示內(nèi)核由待機(jī)狀態(tài)退出。

待機(jī)模式可實現(xiàn)系統(tǒng)的最低功耗。該模式是在Cortex-M3深睡眠模式時關(guān)閉電壓調(diào)節(jié)器。整個1.8V供電區(qū)域被斷電。IRC8M、HXTAL 和 PLL振蕩器也被斷電。SRAM和寄存器內(nèi)容丟失。只有備份的寄存器和待機(jī)電路維持供電。

待機(jī)模式 說明
進(jìn)入 在以下條件下執(zhí)行WFI(等待中斷)或WFE(等待事件)指令: –設(shè)置Cortex?-M3系統(tǒng)控制寄存器中的SLEEPDEEP位 –設(shè)置電源控制寄存器(PWR_CTL)中的STBMOD位 –清除電源控制/狀態(tài)寄存器(PWR_CS)中的WUF位
退出 WKUP引腳的上升沿、RTC鬧鐘事件的上升沿、NRST引腳上外部復(fù)位、FWDGT復(fù)位。
喚醒延時 復(fù)位階段時電壓調(diào)節(jié)器的啟動

3 低功耗的寄存器描述

電源控制寄存器(PWR_CTL),該寄存器的各位描述如下圖所示:

1684245486565uey0p7r2pq

我們通過設(shè)置 PWR_CTL的 STBMOD位,使 CPU 進(jìn)入深度睡眠時進(jìn)入待機(jī)模式。

電源控制/狀態(tài)寄存器( PWR_CS)的各位描述如圖所示。

1684245486948ys3dsyd2c7

通過設(shè)置 PWR_CS的 WUPEN 位,來使能 WKUP 引腳用于待機(jī)模式喚醒。我們還可以從 WUF 來檢查是否發(fā)生了喚醒事件。

4 低功耗具體代碼實現(xiàn)

通過以上介紹,我們了解了進(jìn)入低功耗模式的三種方法,在者三種模式中待機(jī)模式功耗最低。筆者這里使用的是按鍵喚醒,其電路如下:

1684245487308dwt16x8vn9

4.1睡眠模式

睡眠模式很簡單,就是通過以下指令進(jìn)入睡眠:

__WFI();	
__WFE();

那么以上兩條指令又是啥意思呢?WFI(Wait for interrupt)和WFE(Wait for event)是兩個讓ARM核進(jìn)入low-power standby模式的指令,由ARM architecture定義,由ARM core實現(xiàn)。我們可以在core_cmx3.h(筆者使用的是GD32F207,對應(yīng)的就是core_cmx3.h,其他內(nèi)核類似),中找到以上指令的定義。

static __INLINE void __WFI()                      { __ASM volatile ("wfi"); }
static __INLINE void __WFE()                      { __ASM volatile ("wfe"); }

以上就是把匯編指令都封裝成了諸如__Commnad()的函數(shù)形式,并且預(yù)編譯為二進(jìn)制包。那么以上指令都能讓ARM進(jìn)入睡眠模式,又有啥區(qū)別呢?

對WFI來說,執(zhí)行WFI指令后,ARM core會立即進(jìn)入low-power standby state,直到有WFI Wakeup events發(fā)生。

而WFE則稍微不同,執(zhí)行WFE指令后,根據(jù)Event Register(一個單bit的寄存器,每個PE一個)的狀態(tài),有兩種情況:如果Event Register為1,該指令會把它清零,然后執(zhí)行完成(不會standby);如果Event Register為0,和WFI類似,進(jìn)入low-power standby state,直到有WFE Wakeup events發(fā)生。

總結(jié)一下,這兩條指令的作用都是令MCU進(jìn)入休眠/待機(jī)狀態(tài)以便降低功耗,但是略有區(qū)別:

WFI: wait for Interrupt 等待中斷,即下一次中斷發(fā)生前都在此hold住不干活

WFE: wait for Events 等待事件,即下一次事件發(fā)生前都在此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(); //進(jìn)入睡眠模式,等待中斷喚醒  方式一
        __WFE(); //方式二
    }
}

進(jìn)入睡眠模式也可調(diào)用庫函數(shù)。

void pmu_to_sleepmode(uint8_t sleepmodecmd)

值得注意的是,這里不能用滴答定時器來延時,因為這里使用的是中斷方式實現(xiàn)的。

WFI和WFE兩條指令讓MCU進(jìn)入睡眠模式,均可通過按鍵中斷喚醒,但是他們的喚醒本質(zhì)是有區(qū)別的。

https://images2017.cnblogs.com/blog/1138116/201708/1138116-20170815083132084-771850603.png

如上圖所示,圖中的藍(lán)色虛線箭頭標(biāo)出了中斷信號的傳輸路徑,而紅色箭頭標(biāo)出了事件的傳輸路徑。雖然中斷和事件的產(chǎn)生源都是一樣的,都是通過按鍵產(chǎn)生,但是路徑卻有不同,中斷是需要CPU參與的,需要軟件的中斷服務(wù)函數(shù)才能完成中斷后產(chǎn)生的結(jié)果;事件是靠脈沖發(fā)生器產(chǎn)生一個脈沖,進(jìn)而由硬件自動完成這個事件產(chǎn)生的結(jié)果,當(dāng)然相應(yīng)的聯(lián)動部件需要先設(shè)置好,比如引起DMA操作,AD轉(zhuǎn)換等。

4.2 深度睡眠模式

進(jìn)入深度睡眠模式之后,任何外部中斷都可以喚醒低功耗,但是需要重新配置時鐘,不然系統(tǒng)將以默認(rèn)時鐘(沒有經(jīng)過倍頻)運(yùn)行。筆者這里還是使用外部中斷喚醒。我們先看看主函數(shù)。

/*
    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");

    /* 進(jìn)入深度睡眠模式,設(shè)置電壓調(diào)節(jié)器為低功耗模式,等待中斷喚醒*/
    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進(jìn)入低功耗模式的庫函數(shù),在gd32f20x_pmu.c中實現(xiàn),原型如下:

/*!
    \\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);
}

上述函數(shù)主要節(jié)做了四件事:

1.設(shè)置Cortex-M3系統(tǒng)控制寄存器中的SLEEPDEEP位(SCB_SCR參考Cortex-M3權(quán)威指南182頁)。

2.清除電源控制寄存器(PWR_CTL)中的STBMOD位。

3.通過設(shè)置PWR_CR中LDOLP位選擇電壓調(diào)節(jié)器的模式。

4.執(zhí)行WFI或者WFE匯編指令。

我們可以選擇事件和中斷喚醒兩種方式,選擇哪種方式是根據(jù)庫函數(shù)的第二個參數(shù)決定的,筆者這里使用的中斷喚醒。

16842454884212pavkoprct

深度睡眠模式下MCU喚醒之后,時鐘和頻率是沒有經(jīng)過倍頻的,在GD32F207上,低功耗喚醒之后,是8M頻率運(yùn)行,而正常運(yùn)行是120M。所以,在喚醒停機(jī)模式之后,需要重新配置時鐘。最簡單就是直接調(diào)用庫函數(shù):

SystemInit();

當(dāng)然也可以自己重寫時鐘初始化函數(shù)。

好了,我們最后再看看中斷喚醒的函數(shù):

/*!
    \\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);
    }
}

進(jìn)入中斷后主要是重啟時鐘,然后就會接著運(yùn)行程序。

4.3 待機(jī)模式

待機(jī)模式的功耗最低。待機(jī)模式的具體步驟如下:

1) 使能電源時鐘。

因為要配置電源控制寄存器,所以必須先使能電源時鐘。在庫函數(shù)中,使能電源時鐘的方法是:

rcu_periph_clock_enable(RCU_PMU); //使能 PWR 外設(shè)時鐘
  1. 設(shè)置 WK_UP 引腳作為喚醒源。

使能時鐘之后再設(shè)置 PWR_CS 的WUPEN位,使能WUPEN用于將 CPU 從待機(jī)模式喚醒。在庫函數(shù)中,設(shè)置使能WUPEN用于喚醒 CPU 待機(jī)模式的函數(shù)是:

pmu_wakeup_pin_enable (); //使能喚醒管腳功能

3) 設(shè)置 SLEEPDEEP 位,設(shè)置 STBMOD位,執(zhí)行 WFI 指令,進(jìn)入待機(jī)模式。

進(jìn)入待機(jī)模式, 首先要設(shè)置 SLEEPDEEP 位( 該位在系統(tǒng)控制寄存器( SCB_SCR)的第二位,詳見《 CM3 權(quán)威指南》), 接著我們通過 PWR_CTL設(shè)置 STBMOD位,使得 CPU 進(jìn)入深度睡眠時進(jìn)入待機(jī)模式,最后執(zhí)行 WFI 指令開始進(jìn)入待機(jī)模式,并等待 WK_UP中斷的到來。在庫函數(shù)中,進(jìn)行上面三個功能進(jìn)入待機(jī)模式是在函數(shù)pmu_to_standbymode中實現(xiàn)的:

void pmu_to_standbymode(uint8_t standbymodecmd);

pmu_to_standbymode ()函數(shù)原型如下所示:

/*!
    \\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();
    }
}

該函數(shù)中先配置了STBMOD寄存器位及 SLEEPDEEP 寄存器位,接著調(diào)用__force_stores函數(shù)確保存儲操作完畢后再調(diào)用 WFI 指令,從而進(jìn)入待機(jī)模式。這里值得注意的是,待機(jī)模式也可以使用 WFE 指令進(jìn)入的。

在進(jìn)入待機(jī)模式后,除了被使能了的用于喚醒的 I/O,其余 I/O 都進(jìn)入高阻態(tài),而待機(jī)模式喚醒后,相當(dāng)于復(fù)位 GD32 芯片,程序重新從頭開始執(zhí)行。

4) 最后編寫 WK_UP 中斷/事件函數(shù)。

因為我們通過 WK_UP 中斷/事件( PA0 中斷/事件)來喚醒MCU,所以我們有必要設(shè)置一下該中斷函數(shù),同時我們也通過該函數(shù)里面進(jìn)入待機(jī)模式。

/**
  * @brief  用于檢測按鍵是否被長時間按下
  * @param  無
  * @retval 1 :按鍵被長時間按下  0 :按鍵沒有被長時間按下
  */
uint8_t pwr_check_standby(void)
{
    uint8_t downCnt = 0;    //記錄按下的次數(shù)
    uint8_t upCnt = 0; //記錄松開的次數(shù)

    while(1) //死循環(huán),由return結(jié)束
    {
        if(RESET == gpio_input_bit_get(GPIOA, GPIO_PIN_0))//檢測到按下按鍵
        {
            led_on(LED1);led_on(LED2);led_on(LED3);led_on(LED4); //點(diǎn)亮所有LED燈

            downCnt++; //記錄按下次數(shù)
            upCnt=0; //清除按鍵釋放記錄
            Delay(0xFFFF);
            if(downCnt>=100) //按下時間足夠
            {
                led_off(LED1);led_off(LED2);led_off(LED3);led_off(LED4);
                return 1;  //檢測到按鍵被時間長按下
            }
        }
        else 
        {
            upCnt++;  //記錄釋放次數(shù)
            if(upCnt>5)	 //連續(xù)檢測到釋放超過5次
            {
                led_off(LED1);led_off(LED2);led_off(LED3);led_off(LED4); //關(guān)閉所有LED燈
                return 0; //按下時間太短,不是按鍵長按操作
            }
        }
    }
}

通過以上幾個步驟的設(shè)置,我們就可以使用 GD32 的待機(jī)模式了,并且可以通過 WK_UP來喚醒 MCU。

主函數(shù)如下:

/*
    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 狀態(tài)位*/
            pmu_flag_clear (PMU_FLAG_RESET_WAKEUP);
            /* 使能WKUP引腳的喚醒功能 */
            pmu_wakeup_pin_enable ();
            /* 進(jìn)入待機(jī)模式,等待喚醒*/
            pmu_to_standbymode(WFI_CMD);
        }
    }
}

在循環(huán)體外使用庫函數(shù) pmu_flag_get檢測 PMU_FLAG_WAKEUP標(biāo)志位,當(dāng)這個標(biāo)志位為SET 狀態(tài)的時候,表示本次系統(tǒng)是從待機(jī)模式喚醒的復(fù)位,否則可能是上電復(fù)位。其中PMU_FLAG_WAKEUP的標(biāo)志位在gd32f20x_pmu.h中定義。

pwr_check_standby()函數(shù)用于檢測漸漸是否長按,當(dāng)長按后就進(jìn)入待機(jī)模式。

5 低功耗實驗現(xiàn)象

5.1睡眠模式

將程序編譯好后下載到板子上,可以看到4個LED依次閃爍,然后熄滅。按下KEY1按鍵,3個LED再次依次閃爍。

16842454887759lwj6pv9ge

圖6

5.2 深度睡眠模式

將程序編譯好后下載到板子上。按下KEY1按鍵,4個LED依次閃爍。串口依次打印信息如下:

1684245489217sm2lujv77e

當(dāng)程序運(yùn)行后會首先深度睡眠模式,當(dāng)按鍵按下后,退出深度睡眠模式,則程序又會繼續(xù)運(yùn)行。

5.3待機(jī)模式

將程序編譯好后下載到板子上。按下按鍵,4個LED依次閃爍。長按KEY1按鍵,MCU進(jìn)入待機(jī)模式,LED熄滅,再次按下KEY1按鍵,LED會同時點(diǎn)亮,直到同時熄滅,松開KEY1按鍵,KEY1按下會使 PA0 引腳產(chǎn)生一個上升沿,從而喚醒系統(tǒng)。

系統(tǒng)喚醒后會進(jìn)行復(fù)位,從頭開始執(zhí)行上述過程,與第一次上電時不同的是,這樣的復(fù)位會使 PWR_FLAG_WU 標(biāo)志位改為 SET 狀態(tài),LED再次依次閃爍。串口打印信息如下。

168424548971232dzb5akrg

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    146

    文章

    16667

    瀏覽量

    347787
  • 電源管理
    +關(guān)注

    關(guān)注

    115

    文章

    6100

    瀏覽量

    143368
  • 低功耗
    +關(guān)注

    關(guān)注

    10

    文章

    2286

    瀏覽量

    103333
  • 開發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    4771

    瀏覽量

    96177
  • GD32
    +關(guān)注

    關(guān)注

    7

    文章

    400

    瀏覽量

    23974
收藏 人收藏

    評論

    相關(guān)推薦

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 1 開發(fā)環(huán)境搭建

    開發(fā)環(huán)境: MDK:Keil 5.30 開發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 GD32F207I-EVAL
    的頭像 發(fā)表于 05-07 23:35 ?1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>1<b class='flag-5'>章</b> <b class='flag-5'>開發(fā)</b>環(huán)境搭建

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 4 GD32啟動流程詳解(Keil版)

    ,所有的一切都需要由開發(fā)者來設(shè)置,這里處理器是沒有堆棧,沒有中斷,更沒有外圍設(shè)備,這些工作是需要軟件來指定的,而且不同的CPU類型、不同大小的內(nèi)存和不同種類的外設(shè),其初始化工作都是不同的。本文將以GD32F207IK (基于Cortex-M3)為例進(jìn)行講解。
    的頭像 發(fā)表于 05-10 09:00 ?1.6w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>4<b class='flag-5'>章</b> <b class='flag-5'>GD32</b>啟動流程詳解(Keil版)

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 7 定時器

    系統(tǒng)滴答定時器一般用來提供“心跳”作用,而GD32定時器最基本功能也是定時,可以設(shè)置不同時間長度的定時。定時器除了最基本的定時功能外,定時器與GPIO有掛鉤使得它可以發(fā)揮強(qiáng)大的作用,比如可以輸出
    的頭像 發(fā)表于 05-11 09:00 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>7<b class='flag-5'>章</b> 定時器

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 8 定時器

    開發(fā)環(huán)境: MDK:Keil 5.30 開發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 PWM輸出的工作原理 脈沖寬度調(diào)制(PWM) ,是英文“Pulse Wi
    的頭像 發(fā)表于 05-12 22:14 ?7508次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>8<b class='flag-5'>章</b> 定時器

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 11 CPU的高級代理-DMA

    或者存儲器和存儲器之間的高速數(shù)據(jù)傳輸,因而被廣泛地使用。早在 8086 的應(yīng)用中就已經(jīng)有 Intel 的 8237 這種典型的 DMA 控制器,而 GD32的 DMA 則是以類似外設(shè)的形式添加到 Cortex 內(nèi)核之外的??梢哉f,DMA就是CPU的高級代理,DMA大大減輕了CPU的負(fù)擔(dān)。
    的頭像 發(fā)表于 05-16 08:59 ?3714次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>11<b class='flag-5'>章</b> CPU的高級代理-DMA

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 12 ADC

    GD32F2系列有 3 個逐次逼近型的ADC,精度為 12 位,有18個多路復(fù)用通道,可以轉(zhuǎn)換來自16個外部通道和2個內(nèi)部通道的模擬信號。其中ADC0 和 ADC1都有 16 個外部通道, ADC2
    的頭像 發(fā)表于 05-16 09:03 ?1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>12<b class='flag-5'>章</b> ADC

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 14 內(nèi)部溫度傳感器

    GD32 有一個內(nèi)部的溫度傳感器,可以用來測量 CPU 及周圍的溫度(TA)。該溫度傳感器在內(nèi)部和 ADCx_IN16 輸入通道相連接,此通道把傳感器輸出的電壓轉(zhuǎn)換成數(shù)字值。溫度傳感器模擬輸入
    的頭像 發(fā)表于 05-17 08:58 ?4884次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>14<b class='flag-5'>章</b> 內(nèi)部溫度傳感器

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 16 RTC

    開發(fā)環(huán)境: MDK:Keil 5.30 開發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 RTC工作原理 1.1 RTC簡介
    的頭像 發(fā)表于 05-18 22:14 ?6759次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>16<b class='flag-5'>章</b> RTC

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 17 看門狗

    開發(fā)環(huán)境: MDK:Keil 5.30 開發(fā)板:GD32F207I-EVAL MCU:GD32F207IK GD32 有兩個看門狗, 一個是
    的頭像 發(fā)表于 06-03 16:00 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>17<b class='flag-5'>章</b> 看門狗

    【圖書分享】《STM32庫開發(fā)實戰(zhàn)指南

    ,可作為高校電子信息、通信工程、信息工程等相關(guān)專業(yè)的教材,也適合作為從事嵌入式領(lǐng)域科技工作者的參考書。目錄前言第一部分 庫開發(fā)初級 1 為什么學(xué)習(xí)STM32 
    發(fā)表于 03-13 17:01

    GD32 MCU原理及固件庫開發(fā)指南》 + 初讀感悟

    GD32 MCU原理固件庫開發(fā)指南這本書內(nèi)容豐富,囊括了GD32中的所有外設(shè),書中首先介紹了如何使用MDK或IAR軟件搭建GD32工程環(huán)境,讓初學(xué)者能快速基于工程上手編程。書中主要對
    發(fā)表于 03-31 22:11

    GD32 MCU原理及固件庫開發(fā)指南》+讀后感

    。 2介紹GD32 MCU快速入門與開發(fā)平臺搭建的方法,包括對軟硬件開發(fā)平臺、調(diào)試工具、GD32
    發(fā)表于 06-06 21:52

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 10 串口通信

    開發(fā)環(huán)境: MDK:Keil 5.30 開發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 串口簡介 USART(Universal Synchronous
    的頭像 發(fā)表于 05-12 22:25 ?9675次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>10<b class='flag-5'>章</b> 串口通信

    GD32開發(fā)實戰(zhàn)指南(基礎(chǔ)) 19 程序加密

    GD32通過讀取芯片唯一ID號來實現(xiàn)程序的保護(hù),防止被抄襲。96位的產(chǎn)品唯一身份標(biāo)識所提供的參考號碼對任意一個GD32微控制器
    的頭像 發(fā)表于 05-20 09:10 ?3901次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>19<b class='flag-5'>章</b> 程序加密

    gd32和stm32哪個好?

    。 首先,我們從GD32說起。GD32是由國內(nèi)的同時表示中心研發(fā)的一種基于ARM Cortex-M3 CPU的微控制器,該平臺具有很高的兼容性、低功耗以及出色的性能。許多GD32產(chǎn)品也
    的頭像 發(fā)表于 08-16 11:32 ?1402次閱讀