You need to enable JavaScript to run this app. Arduino中PROGMEM存储的3维字节数组无法通过变量索引正常访问
优惠活动
大模型
产品
解决方案
定价
更多

Arduino中PROGMEM存储的3维字节数组无法通过变量索引正常访问

问题原因分析
  • AVR架构的Arduino(如Uno、Nano、Pro Mini)采用哈佛存储架构,程序存储区(Flash)和数据存储区(RAM)独立编址,常规C语言的数组下标解引用逻辑默认仅从RAM空间读取数据,无法直接访问Flash内存储的PROGMEM数据。
  • 你编写的硬编码索引赋值语句(如letter[18][0] = letters[L][18][0];)能正常工作,是avr-gcc的编译优化行为:当访问的所有下标为编译期固定常量时,编译器会自动生成适配PROGMEM的读取指令,规避了常规RAM读的错误逻辑。
  • for循环中使用变量i作为索引时,属于运行时动态访问,编译器不会自动插入PROGMEM专用读取逻辑,直接对错误映射的Flash空间地址执行RAM读操作,因此会读取到全零、随机无意义值这类无效数据。
修复方案

所有对PROGMEM数组的访问,无论索引是否为常量,都必须使用Arduino核心提供的专用PROGMEM读取接口,禁止直接使用C数组下标语法赋值。
针对当前的3维uint8_t数组,使用pgm_read_byte()接口逐字节读取即可,修改后的代码如下:

letter[18][0] = pgm_read_byte(&letters[L][18][0]);
letter[18][1] = pgm_read_byte(&letters[L][18][1]);
letter[19][0] = pgm_read_byte(&letters[L][19][0]);
letter[19][1] = pgm_read_byte(&letters[L][19][1]);
for(int i = 20;i<32;i++){
  letter[i][0] = pgm_read_byte(&letters[L][i][0]);
  letter[i][1] = pgm_read_byte(&letters[L][i][1]);
}
注意事项
  • 不要依赖编译器对硬编码PROGMEM访问的自动优化,哪怕是固定常量的索引访问,也统一使用专用接口读取,避免编译器版本迭代、优化等级调整时出现兼容问题。
  • 若后续需要读取PROGMEM中存储的多字节数据(如uint16_t、结构体),需替换为对应数据类型的专用读取接口(如pgm_read_word),不要手动拼接字节,避免大小端序匹配错误。
  • 当前的PROGMEM数组声明写法本身符合规范,不需要修改,问题仅出在访问环节。
  • 原代码循环内的static int test = i;属于无意义代码,静态变量仅在循环首次执行时初始化为20,后续循环的i值变化不会更新该变量,因变量未被实际使用所以不影响运行逻辑,可以直接删除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.29 06:27:04