4. GPIO功耗优化

任务定义

本案例针对单片机系统中GPIO引脚在静态与动态工作时的功耗浪费问题,完成以下目标:配置GPIO为低功耗模式(输入浮空/下拉、输出低电平)、在运行与睡眠状态间切换引脚状态,并通过测量供电电流验证优化效果。任务闭环为:初始化两个LED引脚(一个推挽输出、一个复用为输入)→ 进入睡眠前将引脚置于最低功耗状态 → 唤醒后恢复功能 → 通过电流表观测静态电流差异。

硬件连接与测量拓扑

测试平台:STM32L0系列(或任意支持低功耗模式的Cortex-M0+ MCU),板载3.3V供电,串接万用表(μA档)于VDD回路。

引脚分配:

  • PA5 — LED1(推挽输出,高电平点亮)
  • PA6 — LED2(复用为输入,内部上拉,用于演示浮空输入漏电)
  • PA0 — 外部按键(下降沿唤醒,EXTI中断)
STM32L0 Cortex-M0+ PA5 PA6 PA0 LED1 LED2 KEY μA 电流表 VDD (3.3V) GND 推挽输出 输入+上拉 EXTI唤醒 STOP 模式 电流 ~1μA

代码实现

// gpio_power_opt.c — STM32L0 低功耗GPIO优化示例
#include "stm32l0xx_hal.h"

void GPIO_Init(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef gpio = {0};
    // PA5: 推挽输出,初始低电平(LED灭)
    gpio.Pin = GPIO_PIN_5;
    gpio.Mode = GPIO_MODE_OUTPUT_PP;
    gpio.Pull = GPIO_NOPULL;
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &gpio);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

    // PA6: 输入模式,无上下拉(避免上拉电阻漏电)
    gpio.Pin = GPIO_PIN_6;
    gpio.Mode = GPIO_MODE_INPUT;
    gpio.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &gpio);

    // PA0: EXTI下降沿唤醒
    gpio.Pin = GPIO_PIN_0;
    gpio.Mode = GPIO_MODE_IT_FALLING;
    gpio.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA, &gpio);

    HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}

void EnterLowPowerGPIO(void) {
    // 进入睡眠前:将所有GPIO置于最低功耗状态
    // PA5输出低电平(已为低),PA6保持浮空输入
    // 关键:关闭未使用外设时钟,PA6不接上下拉
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    // PA6已配置为NOPULL浮空输入,无额外漏电路径
}

void ExitLowPowerGPIO(void) {
    // 唤醒后恢复功能(此处仅恢复LED控制)
    // PA5保持输出模式,PA6仍为输入(无需改变)
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_0) {
        // 按键唤醒,翻转LED1状态
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
    }
}

int main(void) {
    HAL_Init();
    GPIO_Init();

    while (1) {
        // 正常运行:LED1闪烁2次
        for (int i = 0; i < 2; i++) {
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
            HAL_Delay(100);
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
            HAL_Delay(100);
        }

        // 进入低功耗前优化GPIO
        EnterLowPowerGPIO();

        // 进入STOP模式(内部RC振荡器关闭,GPIO状态保持)
        HAL_SuspendTick();
        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
        // 唤醒后恢复
        HAL_ResumeTick();
        SystemClockConfig_HSI();  // 重新配置时钟(需自行实现)
        ExitLowPowerGPIO();
    }
}

功耗对比与验证方法

测量步骤:

  1. 将万用表置于μA档,串接在VDD供电回路中。
  2. 烧录程序后,观察正常运行时的电流(LED闪烁期间约2~5mA,视LED限流电阻而定)。
  3. 等待程序进入STOP模式(LED停止闪烁),记录静态电流读数。
  4. 按下PA0按键唤醒,确认LED1翻转,功能正常。

判定标准:

  • STOP模式下电流应小于5μA(STM32L0典型值1.3μA,若PA6配置为内部上拉则电流会升高至约10~20μA,对比可见差异)。
  • 唤醒后LED响应正常,无异常复位。
  • 若将PA6改为内部上拉模式重新测量,STOP电流明显增大,证明GPIO上下拉配置对静态功耗的影响。

关键优化点说明:本案例的核心在于进入低功耗前将GPIO置于无额外漏电路径的状态——输出引脚固定为低电平(避免浮空输出导致半导通)、输入引脚禁用内部上下拉(消除上拉/下拉电阻的静态电流)。实际项目中还需注意未使用的外设时钟关闭、调试接口(SWD)在睡眠时可能产生的漏电,以及外部器件通过GPIO反向馈电的问题。