You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP no_std Rust环境下深度睡眠时持久化数据的实现问题

ESP no_std Rust环境下深度睡眠时持久化数据的实现问题

看起来你卡在了ESP no_std环境下,既要全局访问可写的数据列表,又要让数据在深度睡眠后保留的问题上,我来帮你梳理下可行的解决方案。

首先,咱们先分析你遇到的核心问题:

  • 普通静态变量默认是不可变的,所以没法直接对MEASUREMENTS调用push方法
  • 直接声明&'static mut Vec会报错,因为Rust不允许静态变量持有可变引用——静态初始化必须是编译期常量,而可变引用的构造属于运行时行为
  • 你用#[ram(rtc_fast)]是找对方向了,这个属性能把数据放在RTC快速RAM里,深度睡眠时这块内存不会断电,数据能完整保留下来

接下来给你两种实用的解决办法,都是完全适配no_std环境的:

方法一:用UnsafeCell实现单线程安全的内部可变性

因为你明确说只有一个线程访问数据,完全不需要多线程同步,用core::cell::UnsafeCell是最轻量化的方案:

首先修改静态变量的定义:

use core::cell::UnsafeCell;

#[ram(rtc_fast)]
static MEASUREMENTS: UnsafeCell<Vec<FloatMeasurement, 10>> = UnsafeCell::new(Vec::new());

然后在main里获取可变引用并操作:

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();

    loop {
        // 单线程下,这个unsafe块是安全的,因为我们能确保没有其他线程同时访问
        let measurements = unsafe { &mut *MEASUREMENTS.get() };
        
        println!("Current measurement count: {}", measurements.len());
        
        match measurements.push(FloatMeasurement {
            temperature: 1.0,
            humidity: 2.0,
        }) {
            Ok(_) => println!("Added new measurement!"),
            Err(_) => println!("Measurement buffer is full, need to send data!"),
        }

        // 当数据满了的时候,发送数据然后清空列表
        if measurements.len() == 10 {
            // 这里写你的数据发送逻辑
            println!("Sending all measurements...");
            measurements.clear();
        }

        enter_deep_sleep(peripherals.LPWR, Duration::from_secs(4).into());
    }
}

方法二:用spin Mutex实现无_std的线程安全(更稳妥)

如果你想完全避免unsafe代码,或者未来可能扩展到多线程场景,可以用spin库的Mutex(它原生支持no_std):

首先在Cargo.toml里添加依赖:

spin = { version = "0.9", features = ["no_std"] }

然后修改静态变量和操作逻辑:

use spin::Mutex;

#[ram(rtc_fast)]
static MEASUREMENTS: Mutex<Vec<FloatMeasurement, 10>> = Mutex::new(Vec::new());

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();

    loop {
        // 锁定Mutex获取可变引用,完全安全无需unsafe
        let mut measurements = MEASUREMENTS.lock();
        
        println!("Current measurement count: {}", measurements.len());
        
        let _ = measurements.push(FloatMeasurement {
            temperature: 1.0,
            humidity: 2.0,
        });

        if measurements.len() == 10 {
            println!("Sending all measurements...");
            measurements.clear();
        }

        enter_deep_sleep(peripherals.LPWR, Duration::from_secs(4).into());
    }
}

额外注意点

  1. 确保你的FloatMeasurement类型可以安全存放在RTC RAM里——它的所有字段都是简单数值类型,当前的定义完全符合要求
  2. 深度睡眠唤醒后,RTC RAM里的MEASUREMENTS会保留之前的数据,所以每次唤醒都会继续累加,直到你调用clear()重置
  3. 如果你之前尝试过once_cell,其实它的no_std版本也能用来初始化静态数据,但对于这个场景,上面两种方法更直接高效

备注:内容来源于stack exchange,提问作者Jürgen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:53:08