Answers:
ATmega内核上执行setup()和loop()的部分代码如下:
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
非常简单,但是有serialEventRun()的开销;在那里。
让我们比较两个简单的草图:
void setup()
{
}
volatile uint8_t x;
void loop()
{
x = 1;
}
和
void setup()
{
}
volatile uint8_t x;
void loop()
{
while(true)
{
x = 1;
}
}
x和volatile只是为了确保未对其进行优化。
在生成的ASM中,您得到不同的结果:
您可以看到while(true)只是执行了rjmp(相对跳转)一些指令,而loop()则执行了减法,比较和调用。这是4条指令与1条指令。
要生成上述ASM,您需要使用一个名为avr-objdump的工具。这包含在avr-gcc中。位置因操作系统而异,因此最容易按名称搜索。
avr-objdump可以在.hex文件上运行,但是这些文件缺少原始来源和注释。如果您刚刚构建了代码,则将有一个包含此数据的.elf文件。同样,这些文件的位置因操作系统而异-找到它们的最简单方法是在首选项中打开详细编译,然后查看输出文件的存储位置。
运行命令,如下所示:
avr-objdump -S output.elf> asm.txt
并在文本编辑器中检查输出。
main.c
Arduino IDE使用的标准的一部分。但是,这并不意味着您的草图中包含了HardwareSerial库。实际上,如果你不使用它(它不包含这就是为什么有if (serialEventRun)
在main()
功能如果不使用HardwareSerial库,然后,serialEventRun
将是无效的,因此没有呼叫。
Cybergibbons的答案很好地描述了汇编代码的生成以及这两种技术之间的差异。这旨在作为从实践上的差异来看问题的补充答案,即每种方法在执行时间方面将产生多少差异。
我进行了涉及以下变化的分析:
void loop()
(在编译时会内联)void loop()
(使用__attribute__ ((noinline))
)while(1)
(已优化)while(1)
(通过添加__asm__ __volatile__("");
。这是一条nop
指令,可防止在不导致volatile
变量额外开销的情况下优化循环)void loop()
优化while(1)
void loop()
优化while(1)
草图可以在这里找到。
我将每个草图运行了30秒钟,从而每个积累了300个数据点。delay
每个循环中有一个100毫秒的调用(如果不发生这种情况,就会发生)。
然后,我计算每个循环的平均执行时间,从每个循环中减去100毫秒,然后绘制结果。
http://raw2.github.com/AsheeshR/Arduino-Loop-Analysis/master/Figures/timeplot.png
while(1)
循环void loop
比编译器优化的循环要快 void loop
。avr-gcc
和使用自己的优化标志进行手动编译,而不是依赖Arduino IDE进行帮助(如果需要微秒优化)。
注意:此处的实际时间值不重要,它们之间的区别是。在〜90微秒的执行时间包括向呼叫Serial.println
,micros
和delay
。
注意2:这是使用Arduino IDE及其提供的默认编译器标志完成的。
注3:使用R完成分析(绘图和计算)。