文章目录[隐藏]
原文:https://www.baldengineer.com/arduino-f-macro.html
你可以在任何想到的地方撒上Serial.print()语句,然后就会崩溃:你的代码随机锁定,LED发疯,你已经拥有它。这是怎么回事?你的RAM用完了!
所有这些Serial.print()语句都由c风格的字符串组成。这是“常量字符数组”。为了使这些数组正常工作,它们会在代码开始运行之前加载到ATmega的RAM中。这可能是一个问题,因为2,048字节的RAM不允许太多。
介绍F()宏
搜索整个Arduino参考页面,您将找不到F()宏的一个提及。这是不幸的,因为它是最强大的功能之一,它随IDE的1.0版本一起添加。我继续混合术语“宏”和“函数。”F()实际上不是一个函数,它是一个#define宏,它存在于WString.h中
WString.h:#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
那长串代码告诉编译器在PROGMEM中保留一个字符串,而不允许它使用RAM。
使用F()宏
以下是如何将F()宏与Serial.print()或Lcd.print()一起使用的示例。
Serial.println(F(“Hello World”));
Lcd.print(F(“W”));
这里的所有都是它的。只需用F()包装你的字符串(const字符数组)。
为什么需要F()宏?
请记住,Arduino Uno(以及它的表兄弟)都是基于ATmega328。该微控制器仅提供2,048字节的RAM。2k,就是这样。即使是Uno的大哥Mega2560也只有8K的RAM。
使用“const”关键字怎么样?
#define
vs const post
,const关键字将告诉编译器变量是常量而不能更改。根据所使用的优化,avr-gcc编译器将避免将该值放入RAM中,因为它知道它永远不会改变。但是,该技术不适用于c风格的字符串,也不适用于数组。由于数组基于指针,因为编译器需要将数组放入RAM中,以便指针正常工作。这意味着,所有字符串都需要在使用之前放入RAM中。
F()宏的作用
F()宏告诉编译器将此特定数组保留在PROGMEM中。然后,当需要访问它时,一次将一个字节的数据复制到RAM。这项额外工作的性能开销很小。但是,通过串行或LCD打印字符串是一个非常缓慢的过程,因此几个额外的时钟周期真的无关紧要。
要考虑的权衡
1:无法更改数据
使用F()宏的关键权衡是您不能将它用于您想要更改的数据。运行程序无法更改存储在PROGMEM中的任何内容。事实上,你永远不会想要那样。可以更改PROGMEM的唯一代码是存储在引导分区中的代码,引导分区是引导加载程序所在的位置。
2:仅适用于字符串
另一个权衡是这个宏只适用于字符串。虽然使用PROGMEM来存储像字符的位模式这样的东西很有用,但是这个宏对它没有帮助。如果这是您要存储的那种东西,那么您将需要使用传统的PROGMEM语句来执行此操作。这使得来自Arduino.cc网站的PROGMEM的参考文献得到了很好的解读。
3:不适合大块文本(如HTML)
存储HTML页面是另一个例子,您可能希望在PROGMEM中保留大量文本。除非HTML包含在Serial.print()
或Client.print()
中,否则您将无法使用F()宏。
4:优化
F()宏没有优化内存使用。如果在代码中反复使用相同的字符串,则每个实例都将使用一些PROGMEM。如果您在PROGMEM上运行不足,则可能必须考虑不使用F()宏。
结论
不要等到你的代码开始表现得很奇怪。每当你在print()方法中使用字符串时,养成用F()宏包装字符串的习惯。这样你就不必担心RAM会被浪费在无法改变的东西上
版权声明:本文为CSDN博主「acktomas」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/acktomas/article/details/89451913
暂无评论