5.16 PWR 使用说明

本章说明 N32G41x 标准外设库中 PWR 驱动的文件组成与 11 个公开函数,内容包括可编程电压检测器(PVD)的阈值与滤波配置、NRST 数字滤波与 IWDG 复位使能,以及 SLEEP、STOP 低功耗模式的进入与主稳压器(MR)低功耗配置;配套的 PVD、SLEEP、STOP 三个示例分别演示电压跨阈值中断、按键唤醒 SLEEP 与唤醒后重建时钟的 STOP。功耗模式、PVD 与 PWR 寄存器的位定义请配合用户手册的“电源控制(PWR)”章节阅读,芯片已知问题以勘误手册为准。

5.16.1 相关文件

相对路径 作用
firmware/n32g41x_std_periph_driver/inc/n32g41x_pwr.h 定义 PVD 阈值档位、PWR_CTRL2 写保护键、SLEEP、STOP 与 MR 低功耗模式条目宏,并按 PVD 配置、复位配置、低功耗模式、写保护、标志管理五个区段声明 11 个公开函数
firmware/n32g41x_std_periph_driver/src/n32g41x_pwr.c 实现上述 11 个函数:对 PWR_CTRL、PWR_CTRL2 与 SCB_SCR 做读改写,执行 WFI/WFE 进入低功耗模式,并读取 PVD 标志
projects/n32g41x_EVAL/examples/PWR/ PWR 示例根目录,含 PVD、SLEEP、STOP 3 个示例
projects/n32g41x_EVAL/examples/PWR/PVD/ 该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt
projects/n32g41x_EVAL/bsp/ 三个示例共用的板级支持文件:n32g41x_stb.h 中的按键与 LED 定义、毫秒延时与日志输出函数

5.16.2 API 参考

搜索 API共 11 个函数

以下 11 个公开函数按 n32g41x_pwr.h 的声明顺序分为 5 组;每个条目给出功能摘要与 n32g41x_pwr.c 中该函数正上方的注释原文。

PVD 配置

PWR_PvdEnable、PWR_PVDFilterWidthSet、PWR_PVDLevelConfig

复位配置

PWR_NRSTFilterWidthSet、PWR_EnableIWDGReset

低功耗模式

PWR_EnterSLEEPMode、PWR_EnterSTOPMode、PWR_ConfigMRLPMode、PWR_ConfigMRLPDelay

写保护

PWR_CTRL2WriteProtectionEnable

标志管理

PWR_GetFlagStatus

void PWR_PvdEnable(FunctionalState Cmd)使能或禁用可编程电压检测器(PVD)。
源码注释
name    PWR_PvdEnable.
fun     Enables or disables the Power Voltage Detector(PVD).
param   Cmd:
          - ENABLE
          - DISABLE
return  none

使用提示: 实现按 Cmd 置位或清除 PWR_CTRL 的 PVDEN 位。

void PWR_PVDFilterWidthSet(uint8_t filter_value)调整 PVD 滤波控制计数值。
源码注释
name    PWR_PVDFilterWidthSet.
fun     Adjusting the PVD Filter Control Count value.
param   filter_value(Filter Width = (1/fLSI) * filter_value):
        -0 ~ 0x1F
return  none

使用提示: 实现把 filter_value 写入 PWR_CTRL 位 18:14 的 PVDCNT 字段。

void PWR_PVDLevelConfig(uint32_t level)配置可编程电压检测器(PVD)检测的电压阈值。
源码注释
name    PWR_PVDLevelConfig.
fun     Configures the voltage threshold detected by the Power Voltage Detector(PVD).
param   PWR_PVDLevel (The input parameters must be the following values):
          - PWR_PVD_LEVEL_2V0
          - PWR_PVD_LEVEL_2V2
          - PWR_PVD_LEVEL_2V4
          - PWR_PVD_LEVEL_2V6
          - PWR_PVD_LEVEL_2V8
          - PWR_PVD_LEVEL_3V0
          - PWR_PVD_LEVEL_3V2
          - PWR_PVD_LEVEL_3V4
          - PWR_PVD_LEVEL_3V6
          - PWR_PVD_LEVEL_3V8
          - PWR_PVD_LEVEL_4V0
          - PWR_PVD_LEVEL_4V2
          - PWR_PVD_LEVEL_4V4
          - PWR_PVD_LEVEL_4V6
          - PWR_PVD_LEVEL_4V8
return  none

使用提示: 实现把 level 写入 PWR_CTRL 位 8:5 的 PLS 字段;PWR_PVD_LEVEL_* 宏已按该位序取值。

void PWR_NRSTFilterWidthSet(uint16_t filter_value)调整 NRST 滤波控制计数值。
源码注释
name    PWR_NRSTFilterWidthSet.
fun     Adjusting the NRST Filter Control Count value.
param   filter_value(Filter Width = (1/fSYSCLK) * filter_value):
        -0 ~ 0x7F
return  none

使用提示: 实现把 filter_value 写入 PWR_CTRL 位 25:19 的 NRSTCNT 字段。

void PWR_EnableIWDGReset(FunctionalState Cmd)配置 IWDG 计数器到 0 时是否产生复位请求。
源码注释
name    PWR_EnableIWDGReset.
fun     Configure whether to generate a reset request when the IWDG counter reaches 0.
param   Cmd:
          - ENABLE
          - DISABLE
return  none.

使用提示: 实现按 Cmd 置位或清除 PWR_CTRL 的 IWDGRSTEN 位。

void PWR_EnterSLEEPMode(uint8_t SLEEPONEXIT, uint8_t PWR_SLEEPEntry)进入 SLEEP 模式。
源码注释
name    PWR_EnterSLEEPMode.
fun     Enters SLEEP mode.
param   SLEEPONEXIT (The input parameters must be the following values):
          - PWR_SLEEP_ON_EXIT
          - PWR_SLEEP_NOW
param   PWR_SLEEPEntry (The input parameters must be the following values):
          - PWR_SLEEPENTRY_WFI enter SLEEP mode with WFI instruction
          - PWR_SLEEPENTRY_WFE enter SLEEP mode with WFE instruction
return  none

使用提示: 实现先清除 SCB_SCR 的 SLEEPDEEP,再按 SLEEPONEXIT 置位或清除 SLEEPONEXIT;传入 PWR_SLEEPENTRY_WFE 时执行 __SEV 与两次 __WFE。

void PWR_EnterSTOPMode(uint8_t enter_mode)进入 STOP 模式。
源码注释
name    PWR_EnterSTOPMode.
fun     Enters STOP mode.
param   PWR_STOPEntry (The input parameters must be the following values):
          - PWR_STOPENTRY_WFI (enter STOP mode with WFI instruction)
          - PWR_STOPENTRY_WFE (enter STOP mode with WFE instruction)
return  none

使用提示: 实现先置位 SCB_SCR 的 SLEEPDEEP,退出后再清除;传入 PWR_STOPENTRY_WFE 时执行 __SEV 与两次 __WFE。注释记录的形参名为 PWR_STOPEntry,头文件原型中的形参名为 enter_mode。

void PWR_ConfigMRLPMode(uint32_t Mode)配置主稳压器(MR)低功耗模式。
源码注释
name    PWR_ConfigMRLPMode.
fun     Configure MR lowpower mode.
param   Mode (The input parameters must be the following values):
          - PWR_MRLPMODE_FIXED
          - PWR_MRLPMODE_AUTO
return  none
note    This register has write protection. Before writing PWR_CTRL2, PWR_CTRL2WriteProtectionEnable()
        function must be called, and then write real value to PWR_CTRL2

使用提示: 实现读改写 PWR_CTRL2 的 MRLPEN 位;该寄存器有写保护,写入前需先调用 PWR_CTRL2WriteProtectionEnable。

void PWR_ConfigMRLPDelay(uint16_t delay_value)调整 MR 低功耗模式的使能延迟时间。
源码注释
name    PWR_ConfigMRLPDelay.
fun     Adjusting the MR lowpower mode enable delay time.
param   delay_value ((delay time = delay_value*(Tsysclk*2)));
        -0 ~ 0xFFF
return  none

使用提示: 实现把 delay_value 的低 12 位写入 PWR_CTRL2 位 12:1 的 MRLPDLY 字段。

void PWR_CTRL2WriteProtectionEnable(void)使能 PWR_CTRL2 寄存器写保护。
源码注释
name    PWR_CTRL2WriteProtectionEnable.
fun     Enable the PWR_CTRL2 registers write protection.
param   none
return  none
note    This register has write protection. Before writing PWR_CTRL2, PWR_CTRL2WriteProtectionEnable()
        function must be called, and then write real value to PWR_CTRL2

使用提示: 实现把 PWR_CTRL2 的 KEY 位字段改写为写保护键 0x57103616。

FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG)检查指定的 PWR 标志是否置位。
源码注释
name    PWR_GetFlagStatus.
fun     Checks whether the specified PWR flag is set or not.
param   PWR_FLAG (The input parameters must be the following values):
          - PWR_PVDO_FLAG       PVD Output flag
return  SET or RESET.

使用提示: 实现读取 PWR_CTRLSTS 与 PWR_FLAG 的按位与结果;参数只登记 PWR_PVDO_FLAG,对应 PWR_CTRLSTS 的 PVDO 位。

5.16.3 Demo 示例说明

本节说明 PWR 的 3 个示例:PVD 用可编程电压检测器监测 VDD、在跨过阈值时中断打印,SLEEP 用 WKUP 按键从睡眠模式唤醒 CPU,STOP 进入停止模式并在唤醒后重建系统时钟。

5.16.3.1 PVD 可编程电压检测中断

工程目录: projects/n32g41x_EVAL/examples/PWR/PVD/

初始化日志串口→配置 EXTI Line16 为上升与下降沿触发→设定 PVD 阈值为 2.4 V 并使能 PVD→等待 VDD 跨过阈值→在 PVD 中断中打印电压高于或低于阈值

项目 源码解读
功能 用可编程电压检测器(PVD)监测 VDD,电压跨过 2.4 V 阈值时经 EXTI Line16 触发中断,并在串口打印当前电压高于还是低于阈值。
源码组成 src/main.c:main、EXTI_Configuration、NVIC_Configuration;
inc/main.h:包含 PWR、EXTI、RCC、GPIO 等头文件并声明上述函数;
src/n32g41x_it.c:中断服务函数,含 PVD_IRQHandler;
inc/n32g41x_it.h:中断服务函数声明;
readme.txt:功能、环境与使用说明;
MDK-ARM/、EWARM/:Keil 与 IAR 工程。
关键配置 PVD 阈值由 PWR_PVD_LEVEL_2V4 设为 2.4 V;
PVD 输出接 EXTI Line16,触发沿为上升与下降沿;
NVIC 优先级分组为 NVIC_PriorityGroup_1,PVD_IRQn 的抢占与子优先级均为 0。
USART1 的 TX 为 PA9,波特率 115200,用于日志输出;
系统时钟为 HSI+PLL,N32G412 为 80 MHz,N32G415 为 96 MHz。
程序与数据路径 main 先调用 log_init 打印示例名,再由 EXTI_Configuration 配置 Line16、NVIC_Configuration 使能 PVD_IRQn;
PWR_PVDLevelConfig 写入阈值、PWR_PvdEnable 使能 PVD 后进入空主循环。
VDD 跨过阈值时 PVD_IRQHandler 清除 EXTI 挂起位,按 PWR_GetFlagStatus(PWR_PVDO_FLAG) 的结果打印高于或低于阈值。
主要 API PWR_PVDLevelConfig、PWR_PvdEnable、PWR_GetFlagStatus
验证方法 下载并复位后串口打印 This is a PVD demo;
调节 VDD 使其跨过 2.4 V,串口分别打印 VDD below threshold! 与 VDD above threshold.。
使用提示 阈值可通过修改 PWR_PVD_LEVEL_2V4 参数调整;
支持 N32G412x8L7、N32G412xBL7、N32G415x8L7、N32G415xBL7,开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM V8.50.1。
核心代码解读与移植

示例把 PVD 输出经 EXTI Line16 接到 NVIC,主循环只等待中断发生。

数据路径: PWR_PVDLevelConfig 写入 PWR_CTRL 的 PLS → PWR_PvdEnable 置位 PVDEN → VDD 跨过阈值改变 PVDO → EXTI Line16 触发 PVD_IRQHandler → PWR_GetFlagStatus 读取 PWR_PVDO_FLAG → 串口打印

1. 配置 EXTI Line16 接收 PVD 输出。 PVD 的检测事件内部连到中断线 16,示例先把该线的挂起位清一次,再配成上升与下降沿触发。

src/main.csrc/main.c · EXTI_Configuration
    EXTI_InitType EXTI_InitStructure;

    /* Configure EXTI Line16(PVD Output) to generate an interrupt on rising and
       falling edges */
    EXTI_ClrITPendBit(EXTI_LINE16);
    EXTI_InitStruct(&EXTI_InitStructure);
    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_InitPeripheral(&EXTI_InitStructure);

移植时要同时核对 PVD 所接的 EXTI 线号与触发沿,以及该线对应的中断服务函数。

2. 使能 PVD 中断通道。 PVD_IRQn 的抢占与子优先级都取 0,优先级分组选用一位抢占。

src/main.csrc/main.c · NVIC_Configuration
    NVIC_InitType NVIC_InitStructure;

    /* Configure one bit for preemption priority */
    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);

改动优先级时要同步改这里的抢占与子优先级,并核对与其它中断的相对次序。

3. 设定阈值并打开 PVD。 阈值先由 PWR_PVDLevelConfig 写入 PWR_CTRL 的 PLS 字段,再由 PWR_PvdEnable 置位 PVDEN;此后主循环为空。

src/main.csrc/main.c · main
    /* Configure the PVD Level to 2.4V ,from 2V ~ 4.8V,one step mean add 200mv*/
    PWR_PVDLevelConfig(PWR_PVD_LEVEL_2V4);

    /* Enable the PVD Output */
    PWR_PvdEnable(ENABLE);

    while (1)
    {
    }

移植时按需要的报警电压改 PWR_PVD_LEVEL_* 宏,从 2.0 V 到 4.8 V 每档相差 200 mV。

4. 中断中读标志并打印。 进入中断后先清 EXTI Line16 的挂起位,再用 PWR_GetFlagStatus 判断 PVDO,据此打印电压方向。

src/n32g41x_it.csrc/n32g41x_it.c · PVD_IRQHandler
    if (EXTI_GetStatusFlag(EXTI_LINE16) != RESET)
    {
        /* Clear the EXTI line 16 pending bit */
        EXTI_ClrITPendBit(EXTI_LINE16);

        /* Check PVD output */
        if (PWR_GetFlagStatus(PWR_PVDO_FLAG) != RESET)
        {
            /* VDD is below PVD threshold */
            printf("PVD IRQ: VDD below threshold!\r\n");
        }
        else
        {
            /* VDD is above PVD threshold */
            printf("PVD IRQ: VDD above threshold.\r\n");
        }
    }

改写判断方向或输出内容时,保持先清挂起位再读标志的顺序,避免下次中断被漏掉。

对应源码: src/main.c、src/n32g41x_it.c

5.16.3.2 SLEEP 睡眠模式按键唤醒

工程目录: projects/n32g41x_EVAL/examples/PWR/SLEEP/

初始化日志串口→配置 WKUP 按键为上升沿中断输入→延时 1 s 后进入 SLEEP 模式→WKUP 按键中断唤醒 CPU→打印进入与退出 SLEEP 的信息

项目 源码解读
功能 用 WKUP 按键(PA0)产生外部中断把 CPU 从 SLEEP 模式唤醒;
CPU 停止执行,唤醒后无需重新配置时钟即恢复运行。
源码组成 src/main.c:main、KeyInputExtiInit;
inc/main.h:包含 PWR、EXTI、RCC、GPIO 等头文件,定义 WKUP 按键的端口、引脚与 EXTI 线宏;
src/n32g41x_it.c:中断服务函数,含 KEY_EXTI_IRQHandler;
inc/n32g41x_it.h:中断服务函数声明;
readme.txt:功能、环境与使用说明;
MDK-ARM/、EWARM/:Keil 与 IAR 工程。
关键配置 WKUP 按键为 PA0,配为 GPIO_MODE_INPUT 输入,映射到 EXTI_LINE0,触发沿为上升沿;
NVIC 优先级分组为 NVIC_PriorityGroup_1,EXTI0_IRQn 的抢占与子优先级均为 0。
USART1 的 TX 为 PA9,波特率 115200;
系统时钟为 HSI+PLL,N32G412 为 80 MHz,N32G415 为 96 MHz。
程序与数据路径 main 调用 log_init 后由 KeyInputExtiInit 把 PA0 配为输入、接 EXTI0 并使能 EXTI0_IRQn,清一次挂起标志后进入循环:先 SysTick_Delay_Ms(1000) 延时并打印进入信息,再用 PWR_EnterSLEEPMode(PWR_SLEEP_NOW, PWR_SLEEPENTRY_WFI) 进入 SLEEP,按键中断唤醒后打印退出信息。
主要 API PWR_EnterSLEEPMode
验证方法 下载并复位后串口打印 --- PWR_SLEEP Demo ---,随后每秒打印 Entry SLEEP mode 并进入睡眠;
按下 WKUP 按键唤醒后串口打印 Exit SLEEP mode。
使用提示 评估功耗时应去掉打印;
支持 N32G412x8L7、N32G412xBL7、N32G415x8L7、N32G415xBL7,开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM V8.50.1。
核心代码解读与移植

示例先配置 WKUP 按键的 EXTI0 中断,主循环延时后进入 SLEEP,由按键唤醒并继续执行。

数据路径: KeyInputExtiInit 把 PA0 配为输入并接 EXTI0 → PWR_EnterSLEEPMode(PWR_SLEEP_NOW, PWR_SLEEPENTRY_WFI) 清 SLEEPDEEP 后执行 WFI → 按键按下触发 EXTI0_IRQHandler 清除挂起位 → CPU 继续运行并打印退出信息

1. 用宏给出 WKUP 按键与 EXTI 线。 inc/main.h 把按键端口、引脚源、EXTI 线、中断向量与中断服务函数名集中定义,后续配置都通过这组宏访问。

inc/main.hinc/main.h
/* WKUP EXTI wakeup configuration (PA0 -> EXTI0) */
#define KEY_EXTI_PORT_SOURCE    GPIOA_PORT_SOURCE
#define KEY_EXTI_PIN_SOURCE     GPIO_PIN_SOURCE0

#define KEY_EXTI_LINE           EXTI_LINE0

#define KEY_EXTI_IRQn           EXTI0_IRQn
#define KEY_EXTI_IRQHandler     EXTI0_IRQHandler

换用其它按键时,同步改这组宏的端口、引脚源与 EXTI 线,并保持中断服务函数名与向量一致。

2. 把按键引脚配成输入并接 EXTI0。 KeyInputExtiInit 打开按键所在端口的时钟,把引脚配为输入,再用 GPIO_ConfigEXTILine 选择端口源与引脚源,最后配置 EXTI 线上升沿触发并使能。

src/main.csrc/main.c · KeyInputExtiInit
    /* Enable the GPIO Clock */
    BUTTON_WKUP_CLK_ENABLE;

    /*Configure the GPIO pin as input floating*/
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin        = Pin;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_INPUT;
    GPIO_InitPeripheral(GPIOx, &GPIO_InitStructure);

    /*Configure key EXTI Line to key input  Pin*/
    GPIO_ConfigEXTILine(KEY_EXTI_PORT_SOURCE, KEY_EXTI_PIN_SOURCE);

    /*Configure key EXTI line*/
    EXTI_InitStruct(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = KEY_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitPeripheral(&EXTI_InitStructure);

移植时按实际按键的端口与引脚改 BUTTON_WKUP_PORT、BUTTON_WKUP_PIN 与 GPIO_ConfigEXTILine 的端口源、引脚源。

3. 延时后进入 SLEEP 并打印进出信息。 主循环每次先延时 1 s,打印进入信息后调用 PWR_EnterSLEEPMode 进入 SLEEP,被唤醒后打印退出信息。

src/main.csrc/main.c · main
    while (1)
    {
       /* Insert a long delay */
       SysTick_Delay_Ms(1000);
       log_info("Entry SLEEP mode\n");
       /* Request to enter SLEEP mode*/
       PWR_EnterSLEEPMode(PWR_SLEEP_NOW, PWR_SLEEPENTRY_WFI);
       log_info("Exit SLEEP mode\n");
    }

第一个实参取 PWR_SLEEP_NOW 表示立即休眠,改延时参数可调整两次休眠之间的间隔。

4. 中断服务清除 EXTI 挂起位。 按键中断进入后判断该线的状态标志,若置位则清挂起位,使 CPU 退出 SLEEP 并返回主循环。

src/n32g41x_it.csrc/n32g41x_it.c · KEY_EXTI_IRQHandler
void KEY_EXTI_IRQHandler(void)
{
    if (EXTI_GetStatusFlag(KEY_EXTI_LINE) != RESET)
    {
        EXTI_ClrStatusFlag(KEY_EXTI_LINE);
    }
}

移植时要核对中断服务函数名与启动文件中 EXTI0_IRQHandler 的映射,以及清除挂起位所用标志与 EXTI 线一致。

对应源码: src/main.c、src/n32g41x_it.c、inc/main.h

5.16.3.3 STOP 停止模式按键唤醒

工程目录: projects/n32g41x_EVAL/examples/PWR/STOP/

初始化日志串口→配置 WKUP 按键为上升沿中断输入→延时 1 s 后进入 STOP 模式→WKUP 按键中断唤醒 MCU→重新配置系统时钟并打印退出信息

项目 源码解读
功能 用 WKUP 按键(PA0)的外部中断把 MCU 从 STOP 模式唤醒;
唤醒后重新配置系统时钟再恢复运行。
源码组成 src/main.c:main、KeyInputExtiInit、SetSysClockToPLL;
inc/main.h:包含 PWR、EXTI、RCC、GPIO、FLASH 等头文件,定义 WKUP 按键的端口、引脚与 EXTI 线宏;
src/n32g41x_it.c:中断服务函数,含 KEY_EXTI_IRQHandler;
inc/n32g41x_it.h:中断服务函数声明;
readme.txt:功能、环境与使用说明;
MDK-ARM/、EWARM/:Keil 与 IAR 工程。
关键配置 WKUP 按键为 PA0,配为 GPIO_MODE_INPUT 输入,映射到 EXTI_LINE0,触发沿为上升沿;
NVIC 优先级分组为 NVIC_PriorityGroup_1,EXTI0_IRQn 的抢占与子优先级均为 0。
唤醒后 SetSysClockToPLL(RCC_PLL_SRC_HSI,80000000) 以 HSI 为 PLL 源重建 80 MHz 系统时钟;
USART1 的 TX 为 PA9,波特率 115200。
程序与数据路径 main 调用 log_init 后由 KeyInputExtiInit 把 PA0 接 EXTI0 并使能 EXTI0_IRQn,进入循环:SysTick_Delay_Ms(1000) 延时并打印进入信息,再用 PWR_EnterSTOPMode(PWR_STOPENTRY_WFI) 进入 STOP;
按键唤醒后 SetSysClockToPLL(RCC_PLL_SRC_HSI,80000000) 重建时钟,延时 10 ms、重新 log_init 并打印退出信息。
主要 API PWR_EnterSTOPMode
验证方法 下载并复位后串口打印 --- Reset for STOP ---,随后每秒打印 Entry STOP mode 并进入 STOP;
按下 WKUP 按键唤醒后串口打印 Exit STOP mode。
使用提示 评估功耗时应去掉打印;
唤醒后必须重新配置时钟与串口,readme 说明唤醒后可观察到 LED1 恢复闪烁;
支持 N32G412x8L7、N32G412xBL7、N32G415x8L7、N32G415xBL7,开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM V8.50.1。
核心代码解读与移植

示例先配置 WKUP 按键中断,主循环进入 STOP,唤醒后重建系统时钟再继续运行。

数据路径: KeyInputExtiInit 把 PA0 接 EXTI0 → PWR_EnterSTOPMode(PWR_STOPENTRY_WFI) 置位 SLEEPDEEP 后执行 WFI → 按键唤醒 → SetSysClockToPLL 重新使能 HSI 与 PLL → 打印退出信息

1. 把 WKUP 按键接到 EXTI0 上升沿。 KeyInputExtiInit 用 GPIO_ConfigEXTILine 选择端口源与引脚源,再配置 EXTI0 为中断模式、上升沿触发并使能。

src/main.csrc/main.c · KeyInputExtiInit
    /*Configure key EXTI Line to key input  Pin*/
    GPIO_ConfigEXTILine(KEY_EXTI_PORT_SOURCE, KEY_EXTI_PIN_SOURCE);

    /*Configure key EXTI line*/
    EXTI_InitStruct(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = KEY_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitPeripheral(&EXTI_InitStructure);

移植时按实际唤醒引脚改端口源与引脚源宏,并核对该 EXTI 线在 STOP 模式下具备唤醒能力。

2. 主循环进入 STOP 并在唤醒后重建时钟。 主循环延时 1 s 后打印进入信息并调用 PWR_EnterSTOPMode,被按键唤醒后调用 SetSysClockToPLL 恢复时钟,再延时 10 ms 并重新初始化日志。

src/main.csrc/main.c · main
    while (1)
    {
       /* Insert a long delay */
       SysTick_Delay_Ms(1000);
       log_info("Entry STOP mode\n"); 
       /* Request to enter STOP mode*/
       PWR_EnterSTOPMode(PWR_STOPENTRY_WFI);
       /* Configures system clock after wake-up from STOP: enable HSI, PLL and select
          PLL as system clock source */
       SetSysClockToPLL(RCC_PLL_SRC_HSI,80000000);
       SysTick_Delay_Ms(10);
       log_init();
       log_info("\nExit STOP mode\n");
    }

从 STOP 唤醒到时钟重建之间串口不可用,因此退出信息排在 SetSysClockToPLL 与重新 log_init 之后。

3. 时钟重建函数按目标频率选择 PLL 参数。 SetSysClockToPLL 以 80 MHz 为目标选择倍频系数、输出分频与 FLASH 等待周期,并设置各总线分频后把 PLL 切为系统时钟。

src/main.csrc/main.c · SetSysClockToPLL
        case 80000000:
            /* 4MHz * 40 = 160MHz(FVCO) / 2(PLLOD) /1 = 80MHz(Fpll) */
            latency   = FLASH_LATENCY_2;   /* 72MHz < SYSCLK <= 80MHz */
            pllmul    = 40;
            plloutdiv = RCC_PLL_OD_DIV_2;
            pllsysdiv = DISABLE;
            break;
        default:
            return ERROR;
    }

    /* HCLK = SYSCLK */
    RCC_ConfigHclk(RCC_SYSCLK_DIV1);

    /* PCLK2 = HCLK */
    RCC_ConfigPclk2(RCC_HCLK_DIV1);

    /* PCLK1 = HCLK/2 */
    RCC_ConfigPclk1(RCC_HCLK_DIV2);

移植时按实际晶振与目标主频改 pllmul、plloutdiv、pllsysdiv,并同步调整 FLASH_LATENCY 与各总线分频。

对应源码: src/main.c

5.16.4 注意与排障

场景 检查与建议 来源
STOP 模式唤醒后的系统时钟 从 STOP 模式经中断或唤醒事件退出时,系统时钟默认切为 HSI,待时钟源就绪后硬件再自动恢复到进入 STOP 之前的状态;
进入前以 PLL 为系统时钟的,需等待 HSI 或 HSE 就绪后由硬件使能并切回 PLL。
用户手册
STOP 模式的进入被延迟 STOP 模式下若正在执行 FLASH 操作或正在访问 APB 区域,进入 STOP 的时间会分别延迟到内存访问或 APB 访问完成。 用户手册
STOP 模式下可用的唤醒源 STOP 模式下 IWDG、RTC/BTIM1/PVD/COMP 与 USART1/4 可配置为唤醒源,PLL、HSI、HSE 时钟关闭,LSE/LSI 可配置运行,SRAM、寄存器与 GPIO 状态保持。 用户手册
写 PWR_CTRL2 前需先开写保护 PWR_CTRL2 有写保护,修改前需先向该寄存器写入 32 位键 0x57103616,再执行写操作;
主稳压器低功耗模式与延迟时间都由该寄存器控制。
用户手册
PVD 阈值与中断触发 PVD 由 PWR_CTRL.PLS[3:0] 选择 2.0 V~4.8 V 的报警阈值(每档相差 200 mV),由 PWR_CTRL.PVDEN 使能;
PWR_CTRLSTS.PVDO 指示 VDD/VDDA 是否高于阈值,该事件内部连接到 EXTI 中断线 16,可配置上升或下降沿触发中断。
用户手册
滤波器旁路 PWR_CTRL.PVDCNT 与 NRSTCNT 全为 0 时对应滤波器旁路;
NRST 滤波在 STOP 模式下旁路。
用户手册

N32G412、N32G415 系列勘误手册 V1.0.0(2026.6.30)的勘误列表只列出一行 A 版芯片条目,勘误链接列为空,未列出 PWR 相关条目。

国民技术开发套件文档中心

按芯片系列在线查阅国民技术 MCU 开发套件的芯片资料、SDK、驱动 API 与 Demo 示例说明。

© 2026 国民技术股份有限公司 版权所有粤ICP备11069485号本站使用不含 Cookie 的匿名访问统计