预算PIC的有限堆栈大小是一个问题区域,我已调整我的代码以适应这一现实。我目前采用粗略的范例,将密切相关的函数分组到一个模块中,并在模块中声明所有变量全局静态(以减少存储在auto psect中的变量数量,并且可变性问题仅与ISR相关,我考虑。)我不这样做是因为这是一种很好的做法,但实际情况是你有足够的空间来分配整个项目中存在的所有本地函数变量。在8/16位芯片的嵌入式世界中,这是一种合适的方法,只要我确保采取必要的预防措施吗?我也做分配>等事情。用于以太网的256字节RAM(我知道它应该是1500作为标准MTU,但我们有自定义情况和非常有限的RAM)缓冲区并且必须通过指针访问该存储器,因此我可以避免存储器存储的语义。我做错了吗?我的应用程序有效,但我100%愿意接受改进建议。并[c]
答案 0 :(得分:4)
我知道这是4年前被问到的,但仍未得到妥善回答。我相信OP所要求的是他们解决HiTech PICC18 C编译器有效和/或最佳实践限制的方法。正如后面的评论中提到的那样,限制(一个相当糟糕的一个而且Hitech没有很好地宣传)是#34; Hi-Tech编译器只允许256字节的自动变量"。实际上,限制比这更糟糕,因为局部变量和参数总共256个字节。超出此限制时的链接器警告也非常神秘。假设函数在调用树的不同分支上,则编译器可以重叠变量以重用空间。这意味着您可以有效地拥有超过256个字节。但请注意,中断处理程序(如果使用优先级方案,则为处理程序)具有自己的调用树,该调用树共享256字节的本地/参数块。
<强>当地人强> 减少本地所需空间的两种解决方案是:使本地全局化或使其成为静态。使它们保持静态可以保持范围相同,并且如果没有从中断调用函数是安全的(编译器不允许出租)。这可能是首选方案。缺点是编译器不能重用这些变量的位置来减少总体内存消耗。将变量移动到全局范围允许重用,但重用管理必须由程序员管理。可能最好的平衡是使简单变量成为静态变量,但要将大块内存(如字符串缓冲区)全局化并仔细重用它们。
小心初始化。
foo()
{
int myvar = 5;
}
必须改为
foo()
{
static int myvar;
myvar = 5;
}
<强>参数强> 如果你在参数调用树中传递大量数据,你将很快遇到相同的256字节限制。这里你最好的选择可能是将一个指针传递给全局分配的&#34; options&#34 ;.或者你可以拥有由顶层调用者设置并由callees在树下读取的全局设置变量。这真的取决于软件的设计哪种方法更好。
我一直在努力解决与OP相同的问题,我认为从长远来看,最好的选择是不再使用Hitech编译器。编译器编写者在一个块中分配所有本地/参数的优化决策仅适用于非常小的ram大小PICS。对于大型PICS,在达到设备的ram大小之前,你将远离本地/ param。然后你必须开始乱码你的代码以适应不正常的编译器。
总结......是的,您的方法是有效的。但是,如果合适的话,请考虑简单地使本地化为静态,因为通常,缩小范围会使代码更安全。
答案 1 :(得分:2)
虽然C18编译器使用一些FSR(指针)来管理数据堆栈,但听起来像Microchip的新XC8编译器使用编译堆栈,因此您应该确切知道堆栈在编译时占用了多少空间。您还将确切知道每个堆栈变量的存储位置。我在XC8 user's guide中读到了所有这些,听起来很棒。假设您正在使用XC8,该功能应该使这个问题没有实际意义。
答案 2 :(得分:1)
我对内存有限的芯片的编译器/链接器的经验是,只要你不使用递归函数并告知编译器,那么编译器就能够确定最小的堆栈空间量需要。
我甚至看到编译器为每个变量赋予自动存储一个全局固定的地址(根本没有堆栈),其中几个变量被分配给重叠的内存,只要它们的生命周期没有重叠。
进行(速度或空间)优化时的一般建议是:进行测量以证明您的优化实际上具有积极效果。
答案 3 :(得分:0)
由于你几乎没有内存,你必须计算RAM的每个字节。使用局部变量(auto)允许在需要的地方重用内存(函数中的本地)。将变量移动到全局静态地址空间时,可以为每个变量提供唯一的空间。这是地址空间的浪费。
Microchip编译器允许不同的变量共享相同的地址。我手边没有文档,但这可以通过编译指示完成。
但您需要的是对RAM要求的分析。当您看到堆栈无法容纳所有变量但自动变量会减少全局内存使用时,您应该考虑使用启动代码和链接描述文件来增加堆栈大小。
答案 4 :(得分:0)
最好的方法是选择符合要求的硬件。
周围的微控制器成本只有几美元,但可以节省数千美元的开发成本。如果这是一个爱好发展,你的努力可能不算数。但在现实世界中,您经常可以找到仅考虑硬件成本的硬件。
特别是PIC18不是紧凑型代码的最佳示例,闪存也存在问题。
答案 5 :(得分:0)
有点晚了,但您还应该仔细查看C18编译器用户指南(如果您使用的是此编译器)。
您可以通过静态分配局部变量(覆盖auto关键字)来显着减少堆栈。更好的是,您可以使用覆盖存储标识符,它允许将不同的非重叠生命周期变量放在同一地址,从而最大限度地减少RAM。 (C18编译器必须在非扩展模式下运行。)
答案 6 :(得分:0)
这种迁移声音很明显,但尽量不要在8位前导上使用16位变量。 16位变量很好,需要更大的结构,但在有限的(8位)架构中,16位aritmetic是一种快速耗尽RAM和ROM存储器的方法。
如果您尝试递增16位变量,编译器将包含一个16位增量库,在大多数情况下会占用大量空间。
另外,尽量不要划分或乘法,因为有些控制器是软件实现的。
就个人而言,我在char
进行alwais,当需要进行除法运算时,使用旋转rigth'n'次除以2 n次。
希望这有帮助!