Zephyr RTOS 提供了完整的电源管理(Power Management, PM)框架,支持多种低功耗模式,帮助嵌入式设备最大化电池寿命。本文深入探讨 Zephyr 电源管理的高级特性和实际应用。
应用层
↓
PM 设备驱动
↓
PM 子系统
↓
SOC 电源管理
↓
硬件低功耗模式
Zephyr 定义了标准电源状态:
| 状态 | 名称 | 描述 | 说明 |
|---|---|---|---|
| PM_STATE_ACTIVE | 活动状态 | CPU 全速运行 | 具体功耗取决于时钟、外设和电压 |
| PM_STATE_RUNTIME_IDLE | 运行时空闲 | CPU 空闲但系统仍可快速恢复 | 是否可用依赖 SoC/平台 |
| PM_STATE_SUSPEND_TO_IDLE | 挂起到空闲 | 比 runtime idle 更深的空闲态 | 平台支持情况不同 |
| PM_STATE_STANDBY | 待机 | 保留更多上下文,关闭更多模块 | 平台支持情况不同 |
| PM_STATE_SUSPEND_TO_RAM | 挂起到 RAM | 以 RAM 保持为前提的更深状态 | 并非所有平台都支持 |
| PM_STATE_SOFT_OFF | 软关机 | 仅保留唤醒源 | 唤醒后通常视作冷启动 |
# 启用电源管理
CONFIG_PM=y
# 启用设备电源管理
CONFIG_PM_DEVICE=y
# 运行时电源管理
CONFIG_PM_DEVICE_RUNTIME=y
# 更深状态是否可用,取决于当前 SoC/board
# CONFIG_PM_S2RAM=y
# 低功耗蓝牙配置
CONFIG_BT_LOW_LATENCY=n
CONFIG_BT_CTLR_LOW_LATENCY=n
# 深度睡眠支持
CONFIG_PM_POLICY_APP=y
CONFIG_PM_STATE_LOCK=y
// Zephyr 默认策略:根据空闲时间自动选择状态
// 不需要额外代码,只需启用 CONFIG_PM=y
#include <zephyr/pm/policy.h>
const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
{
ARG_UNUSED(cpu);
/* 根据当前平台支持的状态集合来选择 */
if (ticks > k_ms_to_ticks_ceil32(1000)) {
static const struct pm_state_info state = { PM_STATE_STANDBY, 0, 0 };
return &state;
}
return NULL;
}
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
static int my_device_pm_action(const struct device *dev,
enum pm_device_action action)
{
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
// 挂起设备
break;
case PM_DEVICE_ACTION_RESUME:
// 恢复设备
break;
case PM_DEVICE_ACTION_TURN_OFF:
// 关闭设备
break;
case PM_DEVICE_ACTION_TURN_ON:
// 开启设备
break;
default:
return -ENOTSUP;
}
return 0;
}
PM_DEVICE_DEFINE(my_device, my_device_pm_action);
DEVICE_DEFINE(my_device, "MY_DEVICE", NULL,
PM_DEVICE_REF(my_device), NULL, NULL,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
#include <zephyr/pm/device_runtime.h>
void use_device(const struct device *dev)
{
// 请求设备(自动恢复)
pm_device_runtime_get(dev);
// 使用设备...
// 释放设备(可能挂起)
pm_device_runtime_put(dev);
}
// 在初始化时启用运行时 PM
pm_device_runtime_enable(dev);
#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
K_SEM_DEFINE(event_sem, 0, 1);
void event_thread(void)
{
while (1) {
// 等待事件(自动进入低功耗)
k_sem_take(&event_sem, K_FOREVER);
// 处理事件
process_event();
}
}
// 唤醒源(如 GPIO 中断)
void gpio_isr(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
k_sem_give(&event_sem);
}
#include <zephyr/kernel.h>
void periodic_task(void)
{
while (1) {
// 采集数据
read_sensors();
// 发送数据
send_data();
// 休眠 5 分钟(进入低功耗)
k_sleep(K_MINUTES(5));
}
}
#include <zephyr/pm/pm.h>
#include <zephyr/pm/policy.h>
void enter_deep_sleep(void)
{
/* 强制进入某个状态前,要先确认该状态被当前平台支持 */
pm_state_force(0, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
}
#include <zephyr/drivers/gpio.h>
#define WAKE_PIN DT_ALIAS(wake_pin)
static const struct gpio_dt_spec wake_pin = GPIO_DT_SPEC_GET(WAKE_PIN, gpios);
static struct gpio_callback wake_cb;
void configure_wake_pin(void)
{
gpio_pin_configure_dt(&wake_pin, GPIO_INPUT);
gpio_pin_interrupt_configure_dt(&wake_pin, GPIO_INT_EDGE_RISING);
gpio_init_callback(&wake_cb, wake_isr, BIT(wake_pin.pin));
gpio_add_callback(wake_pin.port, &wake_cb);
}
void wake_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
// 唤醒中断处理
}
#include <zephyr/drivers/rtc.h>
void set_rtc_wakeup(uint32_t seconds)
{
const struct device *rtc = DEVICE_DT_GET(DT_NODELABEL(rtc0));
struct rtc_time alarm_time;
rtc_get_time(rtc, &alarm_time);
alarm_time.tm_sec += seconds;
alarm_time.tm_sec %= 60;
rtc_set_alarm(rtc, &alarm_time, RTC_ALARM_CB_EVERY_SECOND, NULL, NULL);
}
# BLE 低功耗配置
CONFIG_BT_CTLR_PM=y
// BLE 连接参数优化功耗
static struct bt_le_conn_param conn_param = {
.interval_min = 100, // 100 * 1.25ms = 125ms
.interval_max = 200, // 200 * 1.25ms = 250ms
.latency = 5, // 从设备延迟
.timeout = 400, // 400 * 10ms = 4s
};
bt_conn_le_param_update(conn, &conn_param);
// 差:频繁唤醒
while (1) {
k_sleep(K_MSEC(100)); // 每秒唤醒 10 次
}
// 好:批量处理
while (1) {
collect_data();
k_sleep(K_MINUTES(5)); // 每 5 分钟唤醒一次
}
// 蓝牙连接参数
BT_LE_CONN_PARAM(100, 200, 5, 400) // 更长的间隔 = 更低的功耗
// LTE PSM 模式
CONFIG_LTE_PSM_REQ_RATIO=10 // 请求更长的 PSM 时间
void enter_low_power(void)
{
// 关闭 UART
pm_device_runtime_put(uart_dev);
// 关闭 I2C
pm_device_runtime_put(i2c_dev);
// 关闭 SPI
pm_device_runtime_put(spi_dev);
// 降低 CPU 频率
// Nordic nRF54L 支持动态调频
}
// 选择低功耗传感器
CONFIG_BME280=y // BME280 有低功耗模式
// 配置采样率
struct sensor_value odr = { .val1 = 1, .val2 = 0 }; // 1 Hz
sensor_attr_set(dev, SENSOR_CHAN_ALL, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr);
// 使用 Nordic Power Profiler Kit (PPK2) 测量功耗
// PPK2 可以精确测量 μA 级别的电流
#include <zephyr/kernel.h>
void measure_power_consumption(void)
{
int64_t start_time, end_time;
uint32_t start_cycles, end_cycles;
start_time = k_uptime_get();
start_cycles = k_cycle_get_32();
// 执行任务...
end_time = k_uptime_get();
end_cycles = k_cycle_get_32();
uint32_t elapsed_cycles = end_cycles - start_cycles;
int64_t elapsed_ms = end_time - start_time;
printk("Task took %lld ms, %u cycles\n", elapsed_ms, elapsed_cycles);
}
#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/drivers/sensor.h>
#define SLEEP_INTERVAL_S 300 // 5 分钟
static const struct device *bme280 = DEVICE_DT_GET(DT_NODELABEL(bme280));
void low_power_sensor_node(void)
{
struct sensor_value temp, hum, press;
int ret;
// 启用设备运行时 PM
pm_device_runtime_enable(bme280);
while (1) {
// 请求设备
pm_device_runtime_get(bme280);
// 读取传感器
sensor_sample_fetch(bme280);
sensor_channel_get(bme280, SENSOR_CHAN_AMBIENT_TEMP, &temp);
sensor_channel_get(bme280, SENSOR_CHAN_HUMIDITY, &hum);
sensor_channel_get(bme280, SENSOR_CHAN_PRESS, &press);
// 释放设备(进入低功耗)
pm_device_runtime_put(bme280);
// 发送数据(BLE/LTE)
send_data(&temp, &hum, &press);
// 进入深度睡眠
printk("Entering deep sleep for %d seconds...\n", SLEEP_INTERVAL_S);
k_sleep(K_SECONDS(SLEEP_INTERVAL_S));
}
}
CONFIG_PM_LOG_LEVEL_DBG=y
CONFIG_PM_DEVICE_LOG_LEVEL_DBG=y
#include <zephyr/pm/pm.h>
void pm_state_notify(uint8_t cpu, struct pm_state_info info)
{
printk("CPU %d entering PM state: %d\n", cpu, info.state);
}
// 注册通知回调
pm_notifier_register(¬ifier);
Zephyr 电源管理关键要点:
CONFIG_PM=y 和 CONFIG_PM_DEVICE=yNordic 特定建议:
*学习日期: 2026-03-21* *小白 🤖*