我想将一些值保存到EEPROM,还希望通过避免一些变量声明来释放SRAM,但是EEPROM存储器是按字节分配的。
如果要存储一个int值,则必须重复使用一些表达式。我以为我会为它们做一些功能。但是我担心,如果创建一个函数,它仍然会占用SRAM内存,最好声明一个int变量而不是使用EEPROM。
函数和局部变量如何存储在SRAM中?它是否仅存储闪存中功能指针的地址,还是所有变量和命令都存储在堆栈中?
我想将一些值保存到EEPROM,还希望通过避免一些变量声明来释放SRAM,但是EEPROM存储器是按字节分配的。
如果要存储一个int值,则必须重复使用一些表达式。我以为我会为它们做一些功能。但是我担心,如果创建一个函数,它仍然会占用SRAM内存,最好声明一个int变量而不是使用EEPROM。
函数和局部变量如何存储在SRAM中?它是否仅存储闪存中功能指针的地址,还是所有变量和命令都存储在堆栈中?
Answers:
仅函数的数据存储在堆栈中;它的代码停留在闪存中。您不能真正通过使用EEPROM来减少SRAM的使用,因为如您所见,EEPROM无法以相同的方式寻址。读取和存储EEPROM的代码也需要使用一些SRAM-可能与您要保存的SRAM一样多!EEPROM的写入速度也很慢,并且具有有限的生存期(每个字节的写入次数),这两者都使得存储通常放置在堆栈中的临时数据种类不切实际。它更适合保存不经常更改的数据,例如用于批量生产设备的独特设备配置,或捕获不频繁的错误以供以后分析。
编辑: 该函数没有堆栈,直到该函数被调用为止,所以是的,那是当函数的任何数据放入那里时。函数返回后发生的事情是不再保留其堆栈帧(其SRAM的保留区域)。最终它将被另一个函数调用重新使用。这是内存中C堆栈的图。当堆栈框架不再有用时,只需将其释放,即可重新使用其内存。
局部变量和函数参数存储在堆栈中。但是,这不是不使用它们的原因。计算机被设计为以这种方式工作。
堆栈存储器仅在功能激活时才使用。函数返回后,将立即释放内存。堆栈存储器是一件好事。
您不想将递归函数与许多递归级别一起使用,或在堆栈上分配许多大型结构。正常使用是可以的。
6502堆栈只有256个字节,但是Apple II可以正常工作。
AVR(传统上在Arduino板上使用的微控制器系列)是哈佛架构,这意味着可执行代码和变量位于两个单独的存储器中-在这种情况下为闪存和SRAM。可执行代码永远不会离开闪存。
调用函数时,返回地址通常被压入堆栈-例外情况是函数调用发生在调用函数的末尾。在这种情况下,将使用调用调用函数的函数的返回地址代替-它已经在堆栈中。
是否将其他任何数据放入堆栈取决于调用函数和被调用函数中的寄存器压力。寄存器是CPU的工作区域,AVR具有32个1字节寄存器。可以通过CPU指令直接访问寄存器,而SRAM中的数据首先必须存储在寄存器中。只有当参数或局部变量太大或太多而无法容纳在寄存器中时,它们才会被放入堆栈中。但是,结构始终存储在堆栈中。
您可以在此处
阅读有关AVR平台上GCC编译器如何使用堆栈的详细信息:https : //gcc.gnu.org/wiki/avr-gcc#Frame_Layout
阅读“帧布局”和“调用约定”部分。
我一直在努力尝试编写一些示例代码,以演示此处的出色答案所讲的内容,但到目前为止没有成功。原因是编译器积极地优化了东西。到目前为止,即使在函数中使用局部变量,我的测试也根本没有使用堆栈。原因如下:
编译器可以内联函数调用,因此返回地址可能根本不会被压入堆栈。例:
void foo (byte a)
{
digitalWrite (13, a);
}
void loop ()
{
foo (5);
}
编译器将其转换为:
void loop ()
{
digitalWrite (13, 5);
}
没有函数调用,没有使用堆栈。
编译器可以在寄存器中传递参数,从而省去了将参数压入堆栈的麻烦。例:
digitalWrite (13, 1);
编译成:
158: 8d e0 ldi r24, 0x0D ; 13
15a: 61 e0 ldi r22, 0x01 ; 1
15c: 0e 94 05 01 call 0x20a ; 0x20a <digitalWrite>
参数被放入寄存器中,因此不使用堆栈(除了用于调用digitalWrite的返回地址以外)。
编译器会优化掉您不使用的变量。例:
void foo (byte a)
{
unsigned long bar [100];
bar [1] = a;
digitalWrite (9, bar [1]);
}
void loop ()
{
foo (3);
} // end of loop
现在,这是有分配400个字节的“酒吧”难道不是吗?不:
00000100 <_Z3fooh>:
100: 68 2f mov r22, r24
102: 89 e0 ldi r24, 0x09 ; 9
104: 0e 94 cd 00 call 0x19a ; 0x19a <digitalWrite>
108: 08 95 ret
0000010a <loop>:
10a: 83 e0 ldi r24, 0x03 ; 3
10c: 0e 94 80 00 call 0x100 ; 0x100 <_Z3fooh>
110: 08 95 ret
编译器优化了整个数组!它可以表明我们实际上只是在做a digitalWrite (9, 3)
,这就是它所产生的。
故事的寓意:不要试图超越编译器。