隐藏的Arduino宏F()修复随机锁定

原文: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

生成海报
点赞 0

acktomas

我还没有学会写个人说明!

暂无评论

相关推荐

【翻译】arduino 内置示例

内置示例{#top} https://www.arduino.cc/en/Tutorial/BuiltInExamples 内置示例是Arduino软件(IDE)中包含的草图,单击工具栏菜单打开它们&