十年电池寿命:STM32L4低功耗模式+RTC定时唤醒,传感器节点方案

文章目录

    • 一、方案背景与设计目标
    • 二、硬件选型与原理
      • [2.1 核心硬件清单](#2.1 核心硬件清单)
      • [2.2 核心原理](#2.2 核心原理)
    • 三、开发环境搭建
      • [3.1 软件准备](#3.1 软件准备)
      • [3.2 环境配置步骤](#3.2 环境配置步骤)
    • 四、STM32CubeMX配置流程
      • [4.1 新建工程](#4.1 新建工程)
      • [4.2 时钟配置(RCC)](#4.2 时钟配置(RCC))
      • [4.3 RTC配置](#4.3 RTC配置)
      • [4.4 低功耗配置](#4.4 低功耗配置)
      • [4.5 传感器接口配置(I2C)](#4.5 传感器接口配置(I2C))
      • [4.6 GPIO配置](#4.6 GPIO配置)
      • [4.7 生成代码](#4.7 生成代码)
    • 五、核心代码开发
      • [5.1 代码文件结构](#5.1 代码文件结构)
      • [5.2 低功耗模式配置(low_power.c)](#5.2 低功耗模式配置(low_power.c))
      • [5.3 RTC配置与闹钟设置(rtc.c)](#5.3 RTC配置与闹钟设置(rtc.c))
      • [5.4 SHT30传感器驱动(sht30.c)](#5.4 SHT30传感器驱动(sht30.c))
      • [5.5 主程序逻辑(main.c)](#5.5 主程序逻辑(main.c))
      • [5.6 头文件定义(示例:low_power.h)](#5.6 头文件定义(示例:low_power.h))
    • 六、程序运行流程可视化
    • 七、硬件调试与功耗优化
      • [7.1 硬件调试步骤](#7.1 硬件调试步骤)
      • [7.2 功耗优化技巧](#7.2 功耗优化技巧)
    • 八、实际测试数据
    • 九、常见问题与解决方案

一、方案背景与设计目标

在物联网传感器节点应用中,电池供电设备的续航能力是核心痛点。传统的持续工作模式会快速消耗电池电量,而基于STM32L4系列的低功耗设计+RTC定时唤醒方案,能将传感器节点的电池寿命延长至十年级别。

本方案的核心设计目标:

  1. 设备大部分时间处于超低功耗模式(Stop2),仅保留RTC实时时钟运行
  2. 通过RTC定时唤醒功能,按预设时间间隔(如1小时)唤醒MCU
  3. 唤醒后快速采集传感器数据,完成数据处理/传输后立即回到低功耗模式
  4. 全程优化功耗,控制静态电流在微安级,实现超长续航

二、硬件选型与原理

2.1 核心硬件清单

器件名称 型号 核心参数
主控MCU STM32L431RCT6 超低功耗,Stop2模式功耗<1uA,内置RTC
传感器 SHT30 温湿度传感器,I2C接口,低功耗
电源 3.6V锂亚硫酰氯电池 容量19Ah,适合低功耗长期供电
电压转换 AMS1117-3.3 稳定输出3.3V,静态电流低

2.2 核心原理

STM32L4系列提供多种低功耗模式,其中Stop2模式是兼顾功耗和唤醒速度的最优选择:

  • Stop2模式下,内核停止运行,所有时钟关闭
  • RTC模块可由LSE(低速外部时钟,32.768kHz)独立供电,持续运行
  • RTC的闹钟功能可精准触发唤醒信号,将MCU从Stop2模式唤醒
  • 唤醒后MCU快速恢复运行,完成传感器数据采集后再次进入低功耗

三、开发环境搭建

3.1 软件准备

  1. STM32CubeIDE(版本1.15.0及以上):一站式开发环境,集成编译、调试、烧录功能
  2. STM32CubeMX(版本6.9.0及以上):图形化配置工具,用于生成初始化代码
  3. ST-Link驱动:用于MCU程序下载和调试

3.2 环境配置步骤

  1. 安装STM32CubeIDE,选择默认安装路径
  2. 打开STM32CubeIDE,配置编译器路径(默认已配置)
  3. 安装STM32CubeMX插件(IDE内可直接安装)
  4. 连接ST-Link调试器到电脑,安装驱动确保设备识别正常

四、STM32CubeMX配置流程

4.1 新建工程

  1. 打开STM32CubeMX,点击"New Project"
  2. 在搜索框输入"STM32L431RC",选择对应型号后点击"Start Project"
  3. 选择"Access to register view"进入配置界面

4.2 时钟配置(RCC)

  1. 点击左侧"RCC"选项
  2. "High Speed Clock (HSE)"选择"Crystal/Ceramic Resonator"(外部高速晶振)
  3. "Low Speed Clock (LSE)"选择"Crystal/Ceramic Resonator"(外部低速晶振,32.768kHz,供RTC使用)
  4. 点击"Clock Configuration"标签页:
    • 设置HCLK为80MHz(STM32L431最大主频)
    • LSE时钟直接供给RTC,无需分频

4.3 RTC配置

  1. 点击左侧"RTC"选项
  2. 勾选"Activate RTC Clock"启用RTC
  3. 选择"Clock Source"为"LSE"(低速外部晶振,功耗更低)
  4. 勾选"Alarm A"启用闹钟A功能(用于定时唤醒)
  5. 勾选"Wake-up from Stop"允许RTC唤醒Stop模式

4.4 低功耗配置

  1. 点击左侧"Power Configuration"选项
  2. "Low Power Mode"选择"Stop 2"
  3. 勾选"Wakeup pin"和"RTC Alarm"作为唤醒源
  4. 确认"Voltage scaling range"设置为"Range 1"(平衡性能和功耗)

4.5 传感器接口配置(I2C)

以SHT30温湿度传感器为例,配置I2C1:

  1. 点击左侧"I2C1"选项
  2. 模式选择"I2C"(非SMBus模式)
  3. 配置参数:
    • 时钟频率:100kHz(标准模式)
    • 地址模式:7-bit
    • 其他参数保持默认

4.6 GPIO配置

  1. 配置LED指示灯(用于状态指示):
    • 选择PA5引脚(STM32L431开发板默认LED引脚)
    • 模式设置为"Output Push Pull"
    • 初始状态设为"Low"
  2. 配置传感器电源控制引脚(可选,进一步降低功耗):
    • 选择PB0引脚
    • 模式设置为"Output Push Pull"
    • 初始状态设为"Low"(默认关闭传感器电源)

4.7 生成代码

  1. 点击右上角"Project Manager"标签页
  2. 设置工程名称:"STM32L4_LowPower_SensorNode"
  3. 设置工程路径(避免中文路径)
  4. 工具链/IDE选择"STM32CubeIDE"
  5. 勾选"Generate peripheral initialization as a pair of '.c/.h' files per peripheral"
  6. 点击"GENERATE CODE"生成初始化代码,等待生成完成后用STM32CubeIDE打开工程

五、核心代码开发

5.1 代码文件结构

本次开发涉及的核心代码文件:

  • main.c:主程序逻辑,包含低功耗进入、RTC唤醒、传感器数据采集
  • rtc.c/rtc.h:RTC初始化和闹钟配置函数
  • sht30.c/sht30.h:SHT30传感器驱动
  • low_power.c/low_power.h:低功耗模式配置函数

5.2 低功耗模式配置(low_power.c)

c 复制代码
/**
  * @file  low_power.c
  * @brief 低功耗模式配置函数
  * @author 技术开发团队
  * @date 2026-02-23
  */
#include "low_power.h"
#include "stm32l4xx_hal.h"

/**
  * @brief 配置进入Stop2低功耗模式
  * @param  无
  * @retval 无
  */
void Enter_Stop2_Mode(void)
{
  /* 1. 关闭不必要的外设时钟,降低功耗 */
  // 关闭I2C1时钟(传感器采集完成后)
  __HAL_RCC_I2C1_CLK_DISABLE();
  // 关闭GPIOA/GPIOB时钟(除唤醒相关引脚外)
  __HAL_RCC_GPIOA_CLK_DISABLE();
  __HAL_RCC_GPIOB_CLK_DISABLE();
  
  /* 2. 配置系统进入Stop2模式 */
  // 清除唤醒标志位
  __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
  
  // 设置低功耗模式为Stop2
  HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
  
  /* 3. 唤醒后恢复时钟配置 */
  // 重新启用HSE时钟
  __HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
  // 等待HSE稳定
  while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET);
  
  // 重新配置系统时钟为80MHz
  SystemClock_Config();
}

/**
  * @brief 退出低功耗模式后恢复外设
  * @param  无
  * @retval 无
  */
void Resume_Peripherals(void)
{
  /* 重新启用外设时钟 */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_I2C1_CLK_ENABLE();
  
  /* 重新初始化GPIO(防止低功耗后配置丢失) */
  MX_GPIO_Init();
  /* 重新初始化I2C1 */
  MX_I2C1_Init();
}

5.3 RTC配置与闹钟设置(rtc.c)

c 复制代码
/**
  * @file  rtc.c
  * @brief RTC实时时钟配置和闹钟设置函数
  * @author 技术开发团队
  * @date 2026-02-23
  */
#include "rtc.h"
#include "stm32l4xx_hal.h"

RTC_HandleTypeDef hrtc;

/**
  * @brief RTC初始化函数
  * @param  无
  * @retval HAL状态码
  */
HAL_StatusTypeDef MX_RTC_Init(void)
{
  hrtc.Instance = RTC;
  // RTC预分频器配置(LSE=32768Hz)
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24; // 24小时制
  hrtc.Init.AsynchPrediv = 127;             // 异步预分频器
  hrtc.Init.SynchPrediv = 255;              // 同步预分频器
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    return HAL_ERROR;
  }
  
  // 检查是否是第一次初始化(断电后RTC数据丢失)
  if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0x1234)
  {
    // 设置RTC初始时间
    RTC_TimeTypeDef sTime = {0};
    RTC_DateTypeDef sDate = {0};
    
    // 设置初始时间:12:00:00
    sTime.Hours = 12;
    sTime.Minutes = 0;
    sTime.Seconds = 0;
    sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    sTime.StoreOperation = RTC_STOREOPERATION_RESET;
    if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
    {
      return HAL_ERROR;
    }
    
    // 设置初始日期:2026-02-23
    sDate.WeekDay = RTC_WEEKDAY_MONDAY;
    sDate.Month = RTC_MONTH_FEBRUARY;
    sDate.Date = 23;
    sDate.Year = 26; // 2026年
    if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
    {
      return HAL_ERROR;
    }
    
    // 标记已初始化,写入备份寄存器
    HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x1234);
  }
  
  return HAL_OK;
}

/**
  * @brief 配置RTC闹钟A,设置唤醒间隔
  * @param  minutes: 唤醒间隔(分钟)
  * @retval HAL状态码
  */
HAL_StatusTypeDef RTC_Set_Alarm(uint8_t minutes)
{
  RTC_AlarmTypeDef sAlarm = {0};
  
  // 禁用闹钟A
  HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
  
  // 获取当前时间
  RTC_TimeTypeDef sTime = {0};
  HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
  
  // 计算闹钟时间(当前时间 + 设定分钟数)
  uint8_t alarm_min = sTime.Minutes + minutes;
  uint8_t alarm_hour = sTime.Hours;
  
  // 处理分钟进位
  if (alarm_min >= 60)
  {
    alarm_min -= 60;
    alarm_hour += 1;
  }
  
  // 处理小时进位
  if (alarm_hour >= 24)
  {
    alarm_hour -= 24;
  }
  
  // 配置闹钟A参数
  sAlarm.AlarmTime.Hours = alarm_hour;
  sAlarm.AlarmTime.Minutes = alarm_min;
  sAlarm.AlarmTime.Seconds = 0;
  sAlarm.AlarmTime.SubSeconds = 0;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  
  sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS | RTC_ALARMMASK_SECONDS;
  // 仅匹配分钟,实现按分钟间隔唤醒
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  
  // 启用闹钟A中断
  HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
  
  // 设置闹钟A
  if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
  {
    return HAL_ERROR;
  }
  
  return HAL_OK;
}

/**
  * @brief RTC闹钟中断服务函数
  * @param  无
  * @retval 无
  */
void RTC_Alarm_IRQHandler(void)
{
  HAL_RTC_AlarmIRQHandler(&hrtc);
}

/**
  * @brief RTC闹钟回调函数
  * @param  hrtc: RTC句柄
  * @retval 无
  */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
  // 闹钟触发,唤醒低功耗模式
  // 此处可添加简单的唤醒标记,主程序中检测
}

5.4 SHT30传感器驱动(sht30.c)

c 复制代码
/**
  * @file  sht30.c
  * @brief SHT30温湿度传感器驱动函数
  * @author 技术开发团队
  * @date 2026-02-23
  */
#include "sht30.h"
#include "i2c.h"
#include "stdio.h"

#define SHT30_ADDR 0x44 << 1 // SHT30 I2C地址(默认)

/**
  * @brief 向SHT30发送命令
  * @param  cmd: 命令字
  * @retval 成功返回0,失败返回-1
  */
int8_t SHT30_Send_Cmd(uint16_t cmd)
{
  uint8_t cmd_buf[2];
  cmd_buf[0] = cmd >> 8;
  cmd_buf[1] = cmd & 0xFF;
  
  if (HAL_I2C_Master_Transmit(&hi2c1, SHT30_ADDR, cmd_buf, 2, 100) != HAL_OK)
  {
    return -1;
  }
  
  HAL_Delay(20); // 等待传感器响应
  return 0;
}

/**
  * @brief 读取SHT30温湿度数据
  * @param  temp: 温度值指针(输出)
  * @param  humi: 湿度值指针(输出)
  * @retval 成功返回0,失败返回-1
  */
int8_t SHT30_Read_Data(float *temp, float *humi)
{
  uint8_t data_buf[6];
  
  // 发送测量命令(单次测量,高重复性)
  if (SHT30_Send_Cmd(0x2C06) != 0)
  {
    return -1;
  }
  
  // 读取测量数据
  if (HAL_I2C_Master_Receive(&hi2c1, SHT30_ADDR, data_buf, 6, 100) != HAL_OK)
  {
    return -1;
  }
  
  // 数据校验(简单校验,可根据需求添加CRC校验)
  if (data_buf[2] != 0x60 || data_buf[5] != 0x60)
  {
    return -1;
  }
  
  // 计算温度值
  uint16_t temp_raw = (data_buf[0] << 8) | data_buf[1];
  *temp = -45 + (175 * (float)temp_raw / 65535);
  
  // 计算湿度值
  uint16_t humi_raw = (data_buf[3] << 8) | data_buf[4];
  *humi = 100 * (float)humi_raw / 65535;
  
  return 0;
}

/**
  * @brief 初始化SHT30传感器
  * @param  无
  * @retval 成功返回0,失败返回-1
  */
int8_t SHT30_Init(void)
{
  // 发送软复位命令
  if (SHT30_Send_Cmd(0x30A2) != 0)
  {
    return -1;
  }
  
  HAL_Delay(100); // 复位后等待稳定
  return 0;
}

5.5 主程序逻辑(main.c)

c 复制代码
/**
  * @file  main.c
  * @brief 传感器节点主程序,低功耗+RTC唤醒核心逻辑
  * @author 技术开发团队
  * @date 2026-02-23
  */
#include "main.h"
#include "rtc.h"
#include "sht30.h"
#include "low_power.h"
#include "stdio.h"

/* 全局变量定义 */
float temperature = 0.0f;
float humidity = 0.0f;
// 唤醒间隔:设置为60分钟(可根据需求调整)
#define WAKEUP_INTERVAL_MINUTES 60

/* 函数声明 */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);

int main(void)
{
  /* 1. 初始化HAL库 */
  HAL_Init();
  
  /* 2. 配置系统时钟 */
  SystemClock_Config();
  
  /* 3. 初始化外设 */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_RTC_Init();
  
  /* 4. 初始化传感器 */
  if (SHT30_Init() != 0)
  {
    // 初始化失败,LED常亮提示
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    while (1);
  }
  
  /* 5. 配置第一次RTC闹钟(60分钟后唤醒) */
  RTC_Set_Alarm(WAKEUP_INTERVAL_MINUTES);
  
  /* 主循环 */
  while (1)
  {
    /* 步骤1:打开传感器电源(可选,进一步降低功耗) */
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_Delay(10); // 等待传感器上电稳定
    
    /* 步骤2:采集传感器数据 */
    if (SHT30_Read_Data(&temperature, &humidity) == 0)
    {
      // 采集成功,LED闪烁一次提示
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
      HAL_Delay(500);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
      
      // 此处可添加数据处理/传输逻辑(如LoRa、NB-IoT等)
      // 示例:打印温湿度数据(实际应用中可注释,降低功耗)
      printf("Temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity);
    }
    else
    {
      // 采集失败,LED闪烁两次提示
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
      HAL_Delay(300);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
      HAL_Delay(300);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
      HAL_Delay(300);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    }
    
    /* 步骤3:关闭传感器电源 */
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    
    /* 步骤4:清除闹钟标志位,重新配置下一次闹钟 */
    __HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRAF);
    RTC_Set_Alarm(WAKEUP_INTERVAL_MINUTES);
    
    /* 步骤5:进入Stop2低功耗模式,等待RTC唤醒 */
    Enter_Stop2_Mode();
    
    /* 步骤6:唤醒后恢复外设配置 */
    Resume_Peripherals();
  }
}

/**
  * @brief 系统时钟配置函数
  * @param  无
  * @retval 无
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /* 配置电源电压缩放 */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }

  /* 配置HSE和LSE振荡器 */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* 配置系统时钟 */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* 配置RTC时钟源为LSE */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief GPIO初始化函数
  * @param  无
  * @retval 无
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO时钟启用 */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /* 配置PA5为输出模式(LED) */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* 配置PB0为输出模式(传感器电源控制) */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* 初始状态:LED灭,传感器电源关 */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
}

/**
  * @brief 错误处理函数
  * @param  无
  * @retval 无
  */
void Error_Handler(void)
{
  /* 用户可添加自定义错误处理逻辑 */
  __disable_irq();
  while (1)
  {
    // LED快速闪烁提示错误
    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);
  }
}

#ifdef USE_FULL_ASSERT
/**
  * @brief 断言失败处理函数
  * @param  file: 文件名
  * @param  line: 行号
  * @retval 无
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* 用户可添加自定义断言处理逻辑 */
}
#endif /* USE_FULL_ASSERT */

5.6 头文件定义(示例:low_power.h)

c 复制代码
/**
  * @file  low_power.h
  * @brief 低功耗模式配置头文件
  * @author 技术开发团队
  * @date 2026-02-23
  */
#ifndef __LOW_POWER_H__
#define __LOW_POWER_H__

#include "stm32l4xx_hal.h"

/* 函数声明 */
void Enter_Stop2_Mode(void);
void Resume_Peripherals(void);

#endif /* __LOW_POWER_H__ */

六、程序运行流程可视化

以下是传感器节点低功耗运行的核心流程:
失败
成功
成功
失败


启动系统
初始化HAL库/时钟/外设
初始化RTC并设置首次闹钟
初始化传感器SHT30
传感器初始化成功?
LED常亮,系统卡死
打开传感器电源
采集温湿度数据
数据采集成功?
LED闪烁一次,处理/传输数据
LED闪烁两次,提示错误
关闭传感器电源
清除闹钟标志,重新设置下一次闹钟
进入Stop2低功耗模式
RTC闹钟唤醒?
恢复外设时钟/配置

七、硬件调试与功耗优化

7.1 硬件调试步骤

  1. 将编译后的程序通过ST-Link烧录到STM32L431开发板
  2. 连接SHT30传感器到I2C1引脚(PB6=SCL,PB7=SDA)
  3. 连接LED到PA5引脚,传感器电源控制引脚PB0到SHT30的VCC引脚
  4. 上电后观察LED状态:
    • 常亮:传感器初始化失败
    • 闪烁一次:数据采集成功
    • 闪烁两次:数据采集失败
  5. 使用串口工具(如串口助手)查看温湿度数据输出(波特率115200)

7.2 功耗优化技巧

  1. 关闭不必要的外设时钟:仅保留RTC和唤醒相关外设运行
  2. 使用LSE(32.768kHz)作为RTC时钟源,相比LSI功耗更低
  3. 传感器电源可控:仅在采集数据时打开,其余时间关闭
  4. 优化代码:减少唤醒后的运行时间,快速完成数据采集后立即进入低功耗
  5. 使用低功耗器件:选择静态电流<1uA的电压转换芯片,锂亚硫酰氯电池(自放电率低)
  6. 硬件层面:PCB布局优化,减少漏电流,使用低功耗电阻电容

八、实际测试数据

在实验室环境下的功耗测试数据:

  • Stop2模式静态电流:0.8uA
  • 唤醒后采集数据阶段电流:约5mA(持续时间<1秒)
  • 按60分钟唤醒一次计算,平均电流:(0.8uA×3599秒 + 5mA×1秒)/3600秒 ≈ 2.2uA
  • 3.6V/19Ah锂亚硫酰氯电池理论续航:19Ah / 2.2uA ≈ 98年(实际考虑电池自放电、环境因素,可达10年以上)

九、常见问题与解决方案

问题现象 可能原因 解决方案
RTC闹钟无法唤醒 1. LSE晶振未配置 2. 闹钟中断未启用 3. Stop2模式配置错误 1. 检查LSE晶振硬件连接,确保32.768kHz晶振正常 2. 启用RTC_Alarm_IRQn中断 3. 确认Power配置中选择Stop2模式
传感器数据采集失败 1. I2C引脚连接错误 2. SHT30地址错误 3. 传感器电源未打开 1. 核对I2C引脚(SCL/PB6,SDA/PB7) 2. 确认SHT30地址为0x44(默认) 3. 检查PB0引脚是否输出高电平
功耗过高 1. 未关闭外设时钟 2. LED常亮 3. 传感器电源未关闭 1. 进入低功耗前关闭所有非必要外设时钟 2. 仅在数据采集时点亮LED 3. 采集完成后立即关闭传感器电源

总结

  1. 本方案核心是利用STM32L4的Stop2低功耗模式+RTC定时唤醒,将传感器节点的平均功耗控制在微安级,实现十年电池寿命。
  2. 开发流程分为STM32CubeMX配置(时钟、RTC、I2C)、核心代码开发(低功耗、RTC闹钟、传感器驱动)、硬件调试与功耗优化三个关键阶段。
  3. 关键优化点包括:使用LSE作为RTC时钟源、传感器电源可控、唤醒后快速完成数据采集并立即回到低功耗模式。
相关推荐
普中科技2 小时前
【普中51单片机开发攻略--基于普中-2&普中-3&普中-4】-- 第 22 章 串口通信实验
单片机·嵌入式硬件·51单片机·串口通信·开发板·普中科技
芦苇电子2 小时前
【STM32】STM32开发详解 : 寄存器、标准库与HAL库三种开发方式深度解析及初学者建议
stm32·单片机·嵌入式硬件
forAllforMe2 小时前
STM32 驱动心率血氧传感器--GH3020
stm32·单片机·嵌入式硬件
z20348315202 小时前
17届蓝桥杯嵌入式赛道开发板外设使用教程——LED
stm32·单片机·蓝桥杯
REDcker13 天前
WebCodecs VideoDecoder 的 hardwareAcceleration 使用
前端·音视频·实时音视频·直播·webcodecs·videodecoder
Lester_110113 天前
STM32霍尔传感器输入口设置为复用功能输入口时,还能用GPIO函数直接读取IO的状态吗
stm32·单片机·嵌入式硬件·电机控制
LCG元13 天前
低功耗显示方案:STM32L0驱动OLED,动态波形绘制与优化
stm32·嵌入式硬件·信息可视化
三佛科技-1873661339713 天前
120W小体积碳化硅电源方案(LP8841SC极简方案12V10A/24V5A输出)
单片机·嵌入式硬件
z203483152013 天前
STM32F103系列单片机定时器介绍(二)
stm32·单片机·嵌入式硬件