單芯片解決方案,開啟全新體驗——W55MH32 高性能以太網單片機
W55MH32是WIZnet重磅推出的高性能以太網單片機,它為用戶帶來前所未有的集成化體驗。這顆芯片將強大的組件集于一身,具體來說,一顆W55MH32內置高性能Arm? Cortex-M3核心,其主頻最高可達216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲與數據處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協議棧、內置MAC以及PHY,擁有獨立的32KB以太網收發緩存,可供8個獨立硬件socket使用。如此配置,真正實現了All-in-One解決方案,為開發者提供極大便利。
在封裝規格上,W55MH32 提供了兩種選擇:QFN100和QFN68。
W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專為各種復雜工控場景設計。它擁有66個GPIO、3個ADC、12通道DMA、17個定時器、2個I2C、5個串口、2個SPI接口(其中1個帶I2S接口復用)、1個CAN、1個USB2.0以及1個SDIO接口。如此豐富的外設資源,能夠輕松應對工業控制中多樣化的連接需求,無論是與各類傳感器、執行器的通信,還是對復雜工業協議的支持,都能游刃有余,成為復雜工控領域的理想選擇。 同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網關模組等場景,軟件使用方法一致。更多信息和資料請進入網站或者私信獲取。
此外,本W55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網絡通信安全再添保障。
為助力開發者快速上手與深入開發,基于W55MH32L這顆芯片,WIZnet精心打造了配套開發板。開發板集成WIZ-Link芯片,借助一根USB C口數據線,就能輕松實現調試、下載以及串口打印日志等功能。開發板將所有外設全部引出,拓展功能也大幅提升,便于開發者全面評估芯片性能。
若您想獲取芯片和開發板的更多詳細信息,包括產品特性、技術參數以及價格等,歡迎訪問官方網頁,我們期待與您共同探索W55MH32的無限可能。
第二十七章 電源管理——實現低功耗
本章參考資料:《W55MH32參考手冊》。
1 W55MH32的電源管理簡介
電源對電子設備的重要性不言而喻,它是保證系統穩定運行的基礎,而保證系統能穩定運行后,又有低功耗的要求。 在很多應用場合中都對電子設備的功耗要求非常苛刻,如某些傳感器信息采集設備,僅靠小型的電池提供電源,要求工作長達數年之久, 且期間不需要任何維護;由于智慧穿戴設備的小型化要求,電池體積不能太大導致容量也比較小,所以也很有必要從控制功耗入手, 提高設備的續行時間。因此,W55MH32有專門的電源管理外設監控電源并管理設備的運行模式,確保系統正常運行,并盡量降低器件的功耗。
1.1 電源監控器
W55MH32芯片主要通過引腳VDD從外部獲取電源,在它的內部具有電源監控器用于檢測VDD的電壓, 以實現復位功能及掉電緊急處理功能,保證系統可靠地運行。
1.1.1 上電復位與掉電復位(POR與PDR)
當檢測到VDD的電壓低于閾值VPOR及VPDR時,無需外部電路輔助,W55MH32芯片會自動保持在復位狀態,防止因電壓不足強行工作而帶來嚴重的后果。 見下圖,POR與PDR 。在剛開始電壓低于VPOR時(約1.92V), W55MH32保持在上電復位狀態(POR,Power On Reset),當VDD電壓持續上升至大于VPOR時,芯片開始正常運行,而在芯片正常運行的時候, 當檢測到VDD電壓下降至低于VPDR閾值(約1.88V),會進入掉電復位狀態(PDR,Power Down Reset)。
1.1.2 可編程電壓檢測器PVD
上述POR、PDR功能是使用其電壓閾值與外部供電電壓VDD比較,當低于工作閾值時,會直接進入復位狀態,這可防止電壓不足導致的誤操作。 除此之外,W55MH32還提供了可編程電壓檢測器PVD,它也是實時檢測VDD的電壓,當檢測到電壓低于編程的VPVD閾值時, 會向內核產生一個PVD中斷(EXTI16線中斷)以使內核在復位前進行緊急處理。該電壓閾值可通過電源控制寄存器PWR_CSR設置。
使用PVD可配置8個等級,見下表,PVD的閾值等級 。 其中的上升沿和下降沿分別表示類似圖 POR與PDR 中VDD電壓上升過程及下降過程的閾值。
閾值等級 | 條件 | 最小值 | 典型值 | 最大值 | 單位 |
級別 0 | 上升沿 | 2.1 | 2.18 | 2.26 | V |
級別 0 | 下降沿 | 2 | 2.08 | 2.16 | V |
級別 1 | 上升沿 | 2.19 | 2.28 | 2.37 | V |
級別 1 | 下降沿 | 2.09 | 2.18 | 2.27 | V |
級別 2 | 上升沿 | 2.28 | 2.38 | 2.48 | V |
級別 2 | 下降沿 | 2.18 | 2.28 | 2.38 | V |
級別 3 | 上升沿 | 2.38 | 2.48 | 2.58 | V |
級別 3 | 下降沿 | 2.28 | 2.38 | 2.48 | V |
級別 4 | 上升沿 | 2.47 | 2.58 | 2.69 | V |
級別 4 | 下降沿 | 2.37 | 2.48 | 2.59 | V |
級別 5 | 上升沿 | 2.57 | 2.68 | 2.79 | V |
級別 5 | 下降沿 | 2.47 | 2.58 | 2.69 | V |
級別 6 | 上升沿 | 2.66 | 2.78 | 2.9 | V |
級別 6 | 下降沿 | 2.56 | 2.68 | 2.8 | V |
級別 7 | 上升沿 | 2.76 | 2.88 | 3 | V |
級別 7 | 下降沿 | 2.66 | 2.78 | 2.9 | V |
1.2 W55MH32的電源系統
為了方便進行電源管理,W55MH32把它的外設、內核等模塊根據功能劃分了供電區域, 其內部電源區域劃分見下圖,W55MH32的電源系統 :
從框圖了解到,W55MH32的電源系統主要分為備份域電路、內核電路以及ADC電路三部分,介紹如下:
ADC電源及參考電壓(VDDA供電區域)
為了提高轉換精度,W55MH32的ADC配有獨立的電源接口,方便進行單獨的濾波。 ADC的工作電源使用VDDA引腳輸入,使用VSSA作為獨立的地連接, VREF引腳則為ADC提供測量使用的參考電壓。
調壓器供電電路(VDD/1.8V供電區域)
在W55,H32的電源系統中調壓器供電的電路是最主要的部分,調壓器為備份域及待機電路以外的所有數字電路供電,其中包括內核、 數字外設以及RAM,調壓器的輸出電壓約為1.8V,因而使用調壓器供電的這些電路區域被稱為1.8V域。
調壓器可以運行在“運行模式”、“停止模式”以及“待機模式”。在運行模式下,1.8V域全功率運行;在停止模式下1.8V域運行在低功耗狀態, 1.8V區域的所有時鐘都被關閉,相應的外設都停止了工作,但它會保留內核寄存器以及SRAM的內容;在待機模式下,整個1.8V域都斷電, 該區域的內核寄存器及SRAM內容都會丟失(備份區域的寄存器不受影響)。
備份域電路(后備供電區域)
W55MH32的LSE振蕩器、RTC及備份寄存器這些器件被包含進備份域電路中,這 部分的電路可以通過W55MH32的VBAT引腳獲取供電電源, 在實際應用中一般會使用3V的紐扣電池對該引腳供電。
在圖中備份域電路的左側有一個電源開關結構,它的功能類似圖 雙二極管結構 中的雙二極管, 在它的“1”處連接了VBAT電源,“2”處連接了VDD主電源(一般為3.3V), 右側“3”處引出到備份域電路中。當VDD主電源存在時,由于VDD電壓較高, 備份域電路通過VDD供電,節省紐扣電池的電源,僅當VDD掉電時, 備份域電路由紐扣電池通過VBAT供電,保證電路能持續運行,從而可利用它保留關鍵數據。
1.3 W55MH32的功耗模式
按功耗由高到低排列,W55MH32具有運行、睡眠、停止和待機四種工作模式。上電復位后W55MH32處于運行狀態時,當內核不需要繼續運行, 就可以選擇進入后面的三種低功耗模式降低功耗,這三種模式中,電源消耗不同、喚醒時間不同、喚醒源不同,用戶需要根據應用需求, 選擇最佳的低功耗模式。三種低功耗的模式說明見下表,W55MH32的低功耗模式說明:
模式 | 說明 | 進入方式 | 喚醒方式 | 對 1.8V 區域時鐘的影響 | 對 VDD 區域時鐘的影響 | 調壓器 |
睡眠 | 內核停止,所有外設(如 NVIC、SysTick 等)仍運行 |
調用 WFI 命令 調用 WFE 命令 |
任一中斷 喚醒事件 |
內核時鐘關,其他時鐘和 ADC 時鐘無影響 | 無 | 開 |
停止 | 所有時鐘停止 | 配置PWR_CR 寄存器的PDDS + LPDS + SLEEPDEEP 位 + WFI/WFE 命令 | 任一外部中斷(在外部中斷寄存器中設置) | 關閉所有 1.8V 區域的時鐘 | HSI 和 HSE 振蕩器關閉 | 開啟或低功耗模式(依電源控制寄存器設定) |
待機 | 1.8V 電源關閉 | 配置PWR_CR 寄存器的PDDS + SLEEPDEEP 位 + WFI/WFE 命令 | WKUP 引腳上升沿、RTC 鬧鐘事件、NRST 外部復位、IWDG 復位 | - | - | 關 |
從表中可以看到,這三種低功耗模式層層遞進,運行的時鐘或芯片功能越來越少,因而功耗越來越低。
1.3.1 睡眠模式
在睡眠模式中,僅關閉了內核時鐘,內核停止運行,但其片上外設,CM3核心的外設全都還照常運行。有兩種方式進入睡眠模式, 它的進入方式決定了從睡眠喚醒的方式,分別是WFI(wait for interrupt)和WFE(wait for event),即由等待“中斷”喚醒和由“事件”喚醒。 睡眠模式的各種特性見下表,睡眠模式的各種特性:
特性 | 說明 |
立即睡眠 | 在執行 WFI 或 WFE 指令時立即進入睡眠模式。 |
退出時睡眠 | 在退出優先級最低的中斷服務程序后才進入睡眠模式。 |
進入方式 |
內核寄存器的SLEEPDEEP = 0,然后調用 WFI 或 WFE 指令即可進入睡眠模式; 另外若內核寄存器的SLEEPONEXIT=0 時,進入 “立即睡眠” 模式,SLEEPONEXIT=1 時,進入 “退出時睡眠” 模式。 |
喚醒方式 |
如果是使用 WFI 指令睡眠的,則可使用任意中斷喚醒; 如果是使用 WFE 指令睡眠的,則由事件喚醒。 |
睡眠時 | 關閉內核時鐘,內核停止,而外設正常運行,在軟件上表現為不再執行新的代碼。這個狀態會保留睡眠前的內核寄存器、內存的數據。 |
喚醒延遲 | 無延遲。 |
喚醒后 | 若由中斷喚醒,先進入中斷,退出中斷服務程序后,接著執行 WFI 指令后的程序;若由事件喚醒,直接接著執行 WFE 后的程序。 |
1.3.2 停止模式
在停止模式中,進一步關閉了其它所有的時鐘,于是所有的外設都停止了工作,但由于其1.8V區域的部分電源沒有關閉, 還保留了內核的寄存器、內存的信息,所以從停止模式喚醒,并重新開啟時鐘后,還可以從上次停止處繼續執行代碼。 停止模式可以由任意一個外部中斷(EXTI)喚醒,在停止模式中可以選擇電壓調節器為開模式或低功耗模式。 停止模式的各種特性見下表,停止模式的各種特性:
特性 | 說明 |
調壓器低功耗模式 | 在停止模式下調壓器可工作在正常模式或低功耗模式,可進一步降低功耗 |
進入方式 |
內核寄存器的SLEEPDEEP =1,PWR_CR 寄存器中的PDDS=0,然后調用 WFI 或 WFE 指令即可進入停止模式; PWR_CR 寄存器的LPDS=0 時,調壓器工作在正常模式,LPDS=1 時工作在低功耗模式; |
喚醒方式 |
如果是使用 WFI 指令睡眠的,可使用任意 EXTI 線的中斷喚醒; 如果是使用 WFE 指令睡眠的,可使用任意配置為事件模式的 EXTI 線事件喚醒。 |
停止時 | 內核停止,片上外設也停止。這個狀態會保留停止前的內核寄存器、內存的數據。 |
喚醒延遲 | 基礎延遲為 HSI 振蕩器的啟動時間,若調壓器工作在低功耗模式,還需要加上調壓器從低功耗切換至正常模式下的時間。 |
喚醒后 | 若由中斷喚醒,先進入中斷,退出中斷服務程序后,接著執行 WFI 指令后的程序;若由事件喚醒,直接接著執行 WFE 后的程序。喚醒后,會使用 HSI 作為系統時鐘。 |
1.3.3 待機模式
待機模式,它除了關閉所有的時鐘,還把1.8V區域的電源也完全關閉了,也就是說,從待機模式喚醒后,由于沒有之前代碼的運行記錄, 只能對芯片復位,重新檢測boot條件,從頭開始執行程序。它有四種喚醒方式,分別是WKUP(PA0)引腳的上升沿,RTC鬧鐘事件, NRST引腳的復位和IWDG(獨立看門狗)復位。
特性 | 說明 |
進入方式 | 內核寄存器的SLEEPDEEP =1,PWR_CR 寄存器中的PDDS=1,PWR_CR 寄存器中的喚醒狀態位WUF=0,然后調用 WFI 或 WFE 指令即可進入待機模式; |
喚醒方式 | 通過 WKUP 引腳的上升沿,RTC 鬧鐘、喚醒、入侵、時間戳事件或 NRST 引腳外部復位及 IWDG 復位喚醒。 |
待機時 | 內核停止,片上外設也停止;內核寄存器、內存的數據會丟失;除復位引腳、RTC_AF1 引腳及 WKUP 引腳,其它 I/O 口均工作在高阻態。 |
喚醒延遲 | 芯片復位的時間 |
喚醒后 | 相當于芯片復位,在程序表現為從頭開始執行代碼。 |
在以上講解的睡眠模式、停止模式及待機模式中,若備份域電源正常供電, 備份域內的RTC都可以正常運行,備份域內的寄存器的數據會被保存,不受功耗模式影響。
2 電源管理相關的庫函數及命令
W55MH32標準庫對電源管理提供了完善的函數及命令,使用它們可以方便地進行控制,本小節對這些內容進行講解。
2.1 配置PVD監控功能
PVD可監控VDD的電壓,當它低于閾值時可產生PVD中斷以讓系統進行緊急處理, 這個閾值可以直接使用庫函數PWR_PVDLevelConfig配置成前面表 PVD的閾值等級 中說明的閾值等級。
2.2 WFI與WFE命令
我們了解到進入各種低功耗模式時都需要調用WFI或WFE命令,它們實質上都是內核指令, 在庫文件core_cm3.h中把這些指令封裝成了函數,見代碼清單:電源管理-1 :
代碼清單:電源管理-1 WFI與WFE的指令定義(core_cm3.h文件)
/** brief 等待中斷 等待中斷 是一個暫停執行指令 暫停至任意中斷產生后被喚醒 */ #define __WFI __wfi /** brief 等待事件 等待事件 是一個暫停執行指令 暫停至任意事件產生后被喚醒 */ #define __WFE __wfe
對于這兩個指令,我們應用時一般只需要知道,調用它們都能進入低功耗模式, 需要使用函數的格式“__WFI();”和“__WFE();”來調用(因為__wfi及__wfe是編譯器內置的函數,函數內部調用了相應的匯編指令)。 其中WFI指令決定了它需要用中斷喚醒,而WFE則決定了它可用事件來喚醒,關于它們更詳細的區別可查閱《cortex-CM3/CM4權威指南》了解。
2.3 進入停止模式
直接調用WFI和WFE指令可以進入睡眠模式,而進入停止模式則還需要在調用指令前設置一些寄存器位, W55MH32標準庫把這部分的操作封裝到PWR_EnterSTOPMode函數中了,它的定義見代碼清單:電源管理-2 :
代碼清單:電源管理-2 進入停止模式
/** * @brief 進入停止模式 * * @note 在停止模式下所有I/O的會保持在停止前的狀態 * @note 從停止模式喚醒后,會使用HSI作為時鐘源 * @note 調壓器若工作在低功耗模式,可減少功耗,但喚醒時會增加延遲 * @param PWR_Regulator: 設置停止模式時調壓器的工作模式 * @arg PWR_MainRegulator_ON: 調壓器正常運行 * @arg PWR_Regulator_LowPower: 調壓器低功耗運行 * @param PWR_STOPEntry: 設置使用WFI還是WFE進入停止模式 * @arg PWR_STOPEntry_WFI: WFI進入停止模式 * @arg PWR_STOPEntry_WFE: WFE進入停止模式 * @retval None */ void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry) { uint32_t tmpreg = 0; /* 檢查參數 */ assert_param(IS_PWR_REGULATOR(PWR_Regulator)); assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry)); /* 設置調壓器的模式 ------------*/ tmpreg = PWR->CR; /* 清除 PDDS 及 LPDS 位 */ tmpreg &= CR_DS_MASK; /* 根據PWR_Regulator 的值(調壓器工作模式)配置LPDS,MRLVDS及LPLVDS位*/ tmpreg |= PWR_Regulator; /* 寫入參數值到寄存器 */ PWR->CR = tmpreg; /* 設置內核寄存器的SLEEPDEEP位 */ SCB->SCR |= SCB_SCR_SLEEPDEEP; /* 設置進入停止模式的方式-----------------*/ if (PWR_STOPEntry == PWR_STOPEntry_WFI) { /* 需要中斷喚醒 */ __WFI(); } else { /* 需要事件喚醒 */ __WFE(); } /* 以下的程序是當重新喚醒時才執行的,清除SLEEPDEEP位的狀態 */ SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); }
這個函數有兩個輸入參數,分別用于控制調壓器的模式及選擇使用WFI或WFE停止,代碼中先是根據調壓器的模式配置PWR_CR寄存器, 再把內核寄存器的SLEEPDEEP位置1,這樣再調用WFI或WFE命令時,W55MH32就不是睡眠,而是進入停止模式了。 函數結尾處的語句用于復位SLEEPDEEP位的狀態,由于它是在WFI及WFE指令之后的,所以這部分代碼是在W55MH32被喚醒的時候才會執行。
要注意的是進入停止模式后,W55MH32的所有I/O都保持在停止前的狀態,而當它被喚醒時,W55MH32使用HSI作為系統時鐘(8MHz)運行, 由于系統時鐘會影響很多外設的工作狀態,所以一般我們在喚醒后會重新開啟HSE,把系統時鐘設置回原來的狀態。
2.4 進入待機模式
類似地,W55MH32標準庫也提供了控制進入待機模式的函數,其定義見代碼清單:電源管理-3 :
代碼清單:電源管理-3 進入待機模式
/** * @brief 進入待機模式 * @note 待機模式時,除以下引腳,其余引腳都在高阻態: * -復位引腳 * - RTC_AF1 引腳 (PC13) (需要使能侵入檢測、時間戳事件或RTC鬧鐘事件) * - RTC_AF2 引腳 (PI8) (需要使能侵入檢測或時間戳事件) * - WKUP 引腳 (PA0) (需要使能WKUP喚醒功能) * @note 在調用本函數前還需要清除WUF寄存器位 * @param None * @retval None */ void PWR_EnterSTANDBYMode(void) { /* 清除 Wake-up 標志 */ PWR->CR |= PWR_CR_CWUF; /* 選擇待機模式 */ PWR->CR |= PWR_CR_PDDS; /* 設置內核寄存器的SLEEPDEEP位 */ SCB->SCR |= SCB_SCR_SLEEPDEEP; /* 存儲操作完畢時才能進入待機模式,使用以下語句確保存儲操作執行完畢 */ #if defined ( __CC_ARM ) __force_stores(); #endif /* 等待中斷喚醒 */ __WFI(); }
該函數中先配置了PDDS寄存器位及SLEEPDEEP寄存器位,接著調用__force_stores()函數確保存儲操作完畢后再調用WFI指令, 從而進入待機模式。這里值得注意的是,待機模式也可以使用WFE指令進入的,如果您有需要可以自行修改。
在進入待機模式后,除了被使能了的用于喚醒的I/O,其余I/O都進入高阻態, 而從待機模式喚醒后,相當于復位W55MH32芯片,程序重新從頭開始執行。
3 PWR—電源電壓檢測功能
3.1 代碼分析
1. 頭文件包含與全局變量定義
#include #include #include #include "delay.h" #include "w55mh32.h" USART_TypeDef *USART_TEST = USART1;
包含了標準庫的頭文件以及自定義的 delay.h 和 w55mh32.h 頭文件。
定義了一個指向 USART_TypeDef 結構體的指針 USART_TEST,并將其初始化為 USART1,用于后續的串口操作。
2. 函數聲明
void UART_Configuration(uint32_t bound); void PVD_Configuration(void);
聲明了兩個函數,UART_Configuration() 用于配置串口通信,PVD_Configuration()用于配置電源電壓檢測(PVD)功能。
3. main()函數
int main(void) { RCC_ClocksTypeDef clocks; delay_init(); UART_Configuration(115200); RCC_GetClocksFreq(&clocks); printf("n"); printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn", (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000, (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000); printf("PWR PVD Test.n"); PVD_Configuration(); while (1); }
定義了一個 RCC_ClocksTypeDef 類型的變量 clocks,用于存儲系統時鐘頻率信息。
調用 delay_init()函數初始化延時功能。
調用 UART_Configuration()函數配置串口通信,波特率為 115200。
調用 RCC_GetClocksFreq()函數獲取系統時鐘頻率信息,并通過串口打印出來。
調用 PVD_Configuration()函數配置電源電壓檢測功能。
進入無限循環,保持程序運行。
4. PVD_Configuration()函數
void PVD_Configuration(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); EXTI_ClearITPendingBit(EXTI_Line16); EXTI_InitStructure.EXTI_Line = EXTI_Line16; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); /* Enable the PVD Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); PWR_PVDLevelConfig(PWR_PVDLevel_2V9); PWR_PVDCmd(ENABLE); }
定義了 EXTI_InitTypeDef 和 NVIC_InitTypeDef 類型的變量,分別用于配置外部中斷和嵌套向量中斷控制器(NVIC)。
使能 PWR(電源控制)和 BKP(備份域)外設的時鐘。
清除外部中斷線 16 的中斷掛起標志位。
配置外部中斷線 16 為中斷模式,觸發方式為上升沿和下降沿觸發,并使能該中斷線。
配置 NVIC 的優先級分組為 1。
配置 PVD 中斷的優先級,并使能該中斷。
設置 PVD 的閾值為 2.9V,并使能 PVD 功能。
5. UART_Configuration()函數
void UART_Configuration(uint32_t bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART_TEST, &USART_InitStructure); USART_Cmd(USART_TEST, ENABLE); }
定義了 GPIO_InitTypeDef 和 USART_InitTypeDef 類型的變量,分別用于配置 GPIO 和 USART。
使能 USART1 和 GPIOA 外設的時鐘。
配置 GPIOA 的引腳 9 為復用推挽輸出模式,用于 USART1 的發送功能;配置引腳 10 為浮空輸入模式,用于 USART1 的接收功能。
配置 USART1 的波特率、數據位、停止位、奇偶校驗等參數,并使能 USART1。
6. PVD_IRQHandler()函數
void PVD_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line16) != RESET) { if (PWR_GetFlagStatus(PWR_FLAG_PVDO) == SET) { printf("VDD Below the selected PVD thresholdn"); } else { printf("VDD Above the selected PVD thresholdn"); } EXTI_ClearITPendingBit(EXTI_Line16); } }
這是 PVD 中斷處理函數。
檢查外部中斷線 16 的中斷標志位是否被置位。
如果 PVD 輸出標志位(PWR_FLAG_PVDO)被置位,說明電源電壓低于設定的閾值,通過串口輸出相應信息;否則,說明電源電壓高于設定的閾值,也通過串口輸出相應信息。
清除外部中斷線 16 的中斷掛起標志位。
7. SER_PutChar() 和 fputc()函數
int SER_PutChar(int ch) { while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC)); USART_SendData(USART_TEST, (uint8_t)ch); return ch; } int fputc(int c, FILE *f) { /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ if (c == 'n') { SER_PutChar('r'); } return (SER_PutChar(c)); }
SER_PutChar()函數用于向串口發送一個字符,等待發送完成標志位被置位后再發送下一個字符。
fputc()函數是標準庫函數 printf() 的底層實現,將字符發送到串口。如果遇到換行符 n,則先發送回車符 r。
這段代碼通過配置 PVD 功能,實時監測電源電壓,并在電壓高于或低于設定閾值時觸發中斷,通過串口輸出相應的提示信息。同時,還配置了串口通信功能,用于輸出系統時鐘頻率信息和 PVD 監測結果。
3.2 下載驗證
電壓正常情況下不顯示,想要查看可自行添加代碼;如:
while (1) { // 輪詢檢查電壓狀態(每1秒檢查一次) delay_ms(1000); // 延時避免頻繁查詢 if (PWR_GetFlagStatus(PWR_FLAG_PVDO) == SET) { printf("VDD Below PVD threshold (2.9V)n"); } else { printf("VDD Normal (>= 2.9V)n"); // 電壓正常 } }
顯示效果如下:
4 待機及喚醒
4.1 代碼解析
1. 頭文件和全局變量
#include #include #include #include "delay.h" #include "w55mh32.h" USART_TypeDef *USART_TEST = USART1;
包含了標準庫頭文件和自定義的頭文件。
USART_TEST 是一個指向 USART1 的指針,用于后續的串口操作。
2. 函數聲明
void UART_Configuration(uint32_t bound); void GPIO_Configuration(void); uint8_t GetCmd(void);
聲明了三個函數:
UART_Configuration():用于配置串口。
GPIO_Configuration():用于配置 GPIO 引腳。
GetCmd():用于從串口獲取用戶輸入的命令。
3. 主函數 main()
int main(void) { RCC_ClocksTypeDef clocks; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); delay_init(); UART_Configuration(115200); RCC_GetClocksFreq(&clocks); printf("n"); printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn", (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000, (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000); printf("PWR Standby Test.n"); printf("Enable WakeUp Pin - PA0n"); printf("Please Input 's', Come Standby Moden"); PWR_WakeUpPinCmd(ENABLE); while (GetCmd() != 's'); GPIO_Configuration(); PWR_EnterSTANDBYMode(); while (1); }
時鐘和外設使能:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); 使能電源管理外設(PWR)和備份寄存器(BKP)的時鐘。
初始化操作:
delay_init():初始化延時函數。
UART_Configuration(115200):
配置串口波特率為 115200。
RCC_GetClocksFreq(&clocks):
獲取系統時鐘頻率信息。
信息輸出:
通過 printf()函數輸出系統時鐘頻率信息,并提示用戶可以通過輸入 s 使設備進入待機模式。
喚醒引腳使能:
PWR_WakeUpPinCmd(ENABLE):使能喚醒引腳(PA0),用于從待機模式喚醒設備。
等待用戶輸入:
while (GetCmd() != 's');:循環等待用戶從串口輸入字符 s。
GPIO 配置和進入待機模式:
GPIO_Configuration():配置所有 GPIO 引腳為模擬輸入模式。
PWR_EnterSTANDBYMode():使設備進入待機模式。
無限循環:while (1);
進入無限循環,實際上在進入待機模式后不會執行到這里。
4. GPIO_Configuration()函數
void GPIO_Configuration(void) { uint8_t i; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; for (i = 0; i < (GPIOG_BASE - GPIOA_BASE) / 0x400; i++) { GPIO_Init((GPIO_TypeDef *)((APB2PERIPH_BASE + (i + 3) * 0x0400)), &GPIO_InitStructure); } GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; GPIO_Init(GPIOA, &GPIO_InitStructure); }
使能所有 GPIO 端口的時鐘。
配置 GPIO 引腳的初始化結構體,將所有引腳設置為模擬輸入模式,速度為 50MHz。
通過循環和 GPIO_Init()函數將所有 GPIO 端口的引腳都初始化為模擬輸入模式。
5. UART_Configuration()函數
void UART_Configuration(uint32_t bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART_TEST, &USART_InitStructure); USART_Cmd(USART_TEST, ENABLE); }
使能 USART1 和 GPIOA 的時鐘。
配置 PA9 為復用推挽輸出(用于 USART1 的發送),PA10 為浮空輸入(用于 USART1 的接收)。
配置 USART1 的波特率、數據位、停止位、奇偶校驗等參數,并使能 USART1。
6. GetCmd()函數
uint8_t GetCmd(void) { uint8_t tmp = 0; if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { tmp = USART_ReceiveData(USART1); } return tmp; }
檢查 USART1 的接收緩沖區非空標志(USART_FLAG_RXNE)。
如果標志置位,表示接收到了數據,將數據從 USART1 的接收緩沖區讀取到 tmp 變量中并返回。
7. SER_PutChar() 和 fputc()函數
int SER_PutChar(int ch) { while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC)); USART_SendData(USART_TEST, (uint8_t)ch); return ch; } int fputc(int c, FILE *f) { if (c == 'n') { SER_PutChar('r'); } return (SER_PutChar(c)); }
SER_PutChar()函數用于將一個字符發送到串口,等待發送完成標志(USART_FLAG_TC)置位后再發送下一個字符。
fputc()函數是標準庫 printf()函數的底層實現,在發送換行符(n)時會先發送回車符(r),以確保在串口終端上正確顯示。
這段代碼的主要功能是允許用戶通過串口輸入 s 命令使 W55MH32 設備進入待機模式,同時使能了喚醒引腳(PA0),可以在待機模式下通過該引腳喚醒設備。在進入待機模式前,將所有 GPIO 引腳配置為模擬輸入模式以降低功耗。通過串口可以輸出系統時鐘頻率信息和操作提示。
4.2 下載驗證
輸入‘s’進入待機模式:
把PA0引腳拉高,設備喚醒:
-
單片機
+關注
關注
6066文章
44949瀏覽量
648510 -
電源管理
+關注
關注
117文章
6419瀏覽量
145919 -
低功耗
+關注
關注
10文章
2763瀏覽量
104671 -
GPIO
+關注
關注
16文章
1279瀏覽量
53749
發布評論請先 登錄
共赴之約 | 第二十七屆中國北京國際科技產業博覽會圓滿落幕

《BOSCH汽車電氣與電子 》(中文第一版)(完整版)
「正點原子Linux連載」第二十七章SPI實驗
「正點原子STM32Mini板資料連載」第二十七章 紅外遙控實驗
【正點原子FPGA連載】第二十七章gpio子系統下的LED驅動實驗-領航者ZYNQ之linux開發指南
【傾心力作!】i.MX8MM嵌入式linux開發指南+全覆蓋開發資料
CH32V103基礎教程28-DMA (外設到存儲器)
第二十七講 同步時序邏輯電路的設計

模擬電路網絡課件 第二十七節:集成電路運算放大器
羅德與施瓦茨應邀參加第二十七屆空間太赫茲技術國際研討會
【正點原子FPGA連載】第二十七章DS18B20數字溫度傳感器實驗 -摘自【正點原子】新起點之FPGA開發指南_V2.1

晶能光電亮相第二十七屆廣州國際照明展覽會
姍姍來遲!第二十七屆電壓敏學術年會在成都成功召開

邀請函 | CET中電技術邀您參加第二十七屆高速公路信息化大會暨技術產品博覽會

評論