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

Rust开发Arduino Nano时不可变函数参数传入后异常变更

问题分析与解决方案

核心问题

你的问题本质是栈帧损坏导致变量值被意外覆盖:在interrupt::free闭包内,调用ufmt::uwriteln后,栈上的unit变量被修改,导致第二次读取UNIT_PATTERNS[unit]时拿到了错误的值(从0xd4变成0x54,对应UNIT_PATTERNS[0])。

为什么会发生?

Arduino Nano(atmega328p)的栈空间极小(默认通常仅512字节),而interrupt::free闭包内的操作(尤其是uwriteln的格式化输出会占用大量栈空间)可能引发栈溢出,覆盖了栈上的unit变量。第一次打印UNIT_PATTERNS[unit]时unit仍为正确值2,但uwriteln执行过程中栈帧被破坏,unit被改为0,因此传入set_digit时读取到的是UNIT_PATTERNS[0](0x54)。

解决方案

将unit对应的模式值提前取出并存储在interrupt::free闭包外部,避免闭包内栈操作破坏变量:

fn display_inductance(l: u64, serial: &mut impl ufmt::uWrite) {
    let (mut l, unit) = match l {
        0..=9999              => (l, 0),
        10000..=9999999       => (l/1000, 1),
        10000000..=9999999999 => (l/1000000, 2),
        _                     => (l/1000000000, 3)
    };

    // 提前取出单位模式,存在闭包外部栈帧
    let unit_pattern = UNIT_PATTERNS[unit];

    interrupt::free(|cs| {
        let mut state = DISPLAY_STATE.borrow(cs).borrow_mut();
        let state = state.as_mut().unwrap();

        for i in (0..4).rev() {
            let digit = (l%10) as usize;
            set_digit(&mut state.buffer, i, DIGIT_PATTERNS[digit], serial);
            l /= 10;
        }

        ufmt::uwriteln!(serial, "Unit pattern = 0x{:x}", unit_pattern);
        set_digit(&mut state.buffer, 4, unit_pattern, serial);
    });
}

验证方法

可以在闭包内的uwriteln后额外打印unit的值,确认是否被篡改:

ufmt::uwriteln!(serial, "Unit pattern = 0x{:x}, unit = {}", UNIT_PATTERNS[unit], unit);
ufmt::uwriteln!(serial, "Unit pattern again = 0x{:x}", UNIT_PATTERNS[unit]);

如果输出中unit从2变为0,即可确认是栈覆盖导致的问题。

额外优化建议

  • 减少uwriteln在闭包内的使用:调试输出尽量放在闭包外,避免占用闭包内栈空间。
  • 增大栈空间:通过修改链接脚本或编译参数调整atmega328p的栈大小,但需注意不要超过RAM总容量(2KB)。

内容的提问来源于stack exchange,提问作者GutturalWasp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:21:05