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

Attiny1616中如何存储float计算结果到FLASH?PROGMEM及转char尝试失败

解决Attiny1616将float存入FLASH的问题

一、直接存储float到FLASH(PROGMEM支持float)

你之前误以为PROGMEM不支持float是误解,它可以存储任意数据类型,只要声明和读取方式正确。

声明并存储float到PROGMEM

直接用PROGMEM修饰float变量,需声明为const(FLASH为只读存储):

#include <avr/io.h>
#include <avr/pgmspace.h>

int main(void) {
    // 编译时将float存入FLASH
    const float cal_result PROGMEM = 10.83;
    
    // 读取FLASH中的float值
    float read_value = pgm_read_float_near(&cal_result);
    
    while(1){   
    }
}

Attiny1616的FLASH仅16KB,用pgm_read_float_near即可;若芯片FLASH超过64KB,才需要用pgm_read_float_far。

二、存储字符串形式的float到FLASH

你之前的代码问题在于:out是编译时初始化的PROGMEM数组,但buf是运行时赋值的,编译时buf内容不确定,无法用于初始化PROGMEM。分两种场景处理:

场景1:编译时已知float值

直接将字符串常量定义到PROGMEM:

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <string.h>

int main(void) {
    // 编译时将float的字符串形式存入FLASH
    const char float_str[] PROGMEM = "10.83";
    
    // 读取FLASH中的字符串
    char buf[6];
    strcpy_P(buf, float_str); // 使用strcpy_P读取PROGMEM字符串
    
    while(1){   
    }
}

场景2:运行时计算得到的float,需存字符串到FLASH

这种情况无法用PROGMEM(PROGMEM是编译时分配的),必须使用AVR的**自编程(Self-Programming)**功能直接写入FLASH。Attiny1616支持该功能,示例代码如下:

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/boot.h>
#include <avr/interrupt.h>
#include <stdio.h>

// Attiny1616共16KB FLASH,每页128字节,最后一页起始地址为0x3C00
#define FLASH_TARGET_PAGE 0x3C00

void write_str_to_flash(const char* str) {
    uint16_t addr = FLASH_TARGET_PAGE;
    uint8_t idx = 0;
    
    cli(); // 禁用全局中断,避免写入过程被打断
    
    // 擦除目标FLASH页
    boot_page_erase(addr);
    boot_spm_busy_wait(); // 等待擦除完成
    
    // 按字写入FLASH(FLASH以16位字为单位写入)
    while (str[idx] != '\0' && addr < FLASH_TARGET_PAGE + SPM_PAGESIZE) {
        uint16_t write_word = str[idx];
        if (str[idx+1] != '\0') {
            write_word |= ((uint16_t)str[idx+1]) << 8;
            idx++;
        }
        boot_page_fill(addr, write_word);
        addr += 2;
        idx++;
    }
    
    // 提交写入操作
    boot_page_write(FLASH_TARGET_PAGE);
    boot_spm_busy_wait();
    
    sei(); // 恢复全局中断
}

int main(void) {
    char buf[6];
    float cal_result = 10.83;
    
    // 将float转换为字符串
    snprintf(buf, 6, "%.2f", cal_result);
    
    // 写入FLASH
    write_str_to_flash(buf);
    
    // 读取验证
    char read_buf[6] = {0};
    uint16_t read_addr = FLASH_TARGET_PAGE;
    uint8_t read_idx = 0;
    while (read_idx < 5) {
        uint16_t read_word = pgm_read_word(read_addr);
        read_buf[read_idx++] = read_word & 0xFF;
        read_buf[read_idx++] = (read_word >> 8) & 0xFF;
        read_addr += 2;
    }
    
    while(1){   
    }
}

注意:自编程需确保芯片熔丝位的SPMEN位已使能(Attiny1616默认使能),且写入地址不能覆盖当前运行的程序代码,建议选择FLASH末尾页。

总结

  • 编译时确定的float:直接用PROGMEM修饰,通过pgm_read_float_near读取
  • 编译时确定的字符串形式float:定义const char[] PROGMEM,用strcpy_P读取
  • 运行时计算的float:需存字符串到FLASH时,必须使用自编程API写入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:45:20