假设我有以下代码:
int led = 13;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
ledChange(HIGH);
delay(1000);
ledChange(LOW);
delay(1000);
}
void ledChange(int pinState) {
digitalWrite(led, pinState);
}
将digitalWrite(led, pinState);
移动到自己的函数会影响处理时间吗?
当然,单个LED的性能并不重要,但是每个时钟周期都很重要(高采样率,循环中的大量数学运算等)。
答案 0 :(得分:8)
定义为void的函数只是通知编译器/优化器,该函数没有预期的返回值。
因此不会生成用于保存或操纵任何返回值的代码。
这不是Arduino特有的,它是一种通用的C行为。
答案 1 :(得分:7)
是的,你浪费了数十个时钟周期。当你写ledChange(LOW)
时,它被编译成一个CALL类型的指令(它告诉程序计数器寄存器跳转到方法的位置)。
所以,这基本上会编译为:
LOW
放入某个寄存器或堆栈ledChange()
led
,并将其与LOW
某处digitalWrite()
digitalWrite()
请注意,CALL
跳转涉及大量混乱堆栈,并且比常规JMP
指令花费的时间更长。
另一方面,只做digitalWrite(led,LOW)
会:
led
,LOW
并将其放在可访问的地方ditigalWrite()
digitalWrite()
我不完全确定如何在相应的编译代码中传递参数,它可能是调用的部分。另请注意,编译器各不相同,有些比其他编译器更聪明。
您可以看到,对函数的封装使程序在每次运行时占用更多的时钟周期。但是,这并不值得优化;我没有看到这种封装能够减慢Arduino的速度。此外,就像我提到的,一些编译器会优化这些东西。
这与作为void
的函数无关。如果它是一个int
函数,它将会慢得多,因为在返回之前存储int涉及MV
或堆栈操作(忘记了)。
答案 2 :(得分:2)
您可以设置avr-gcc来显示装配输出。检查出来,你可以看到函数的返回类型与代码的大小无关。如果您没有返回任何值,它将不会生成额外的代码。但是,您将收到编译器警告,因此在这种情况下使用void
很好。
如果你使用函数,你可能会有更短的代码,因为你不需要在每次需要时重复函数中的代码(这意味着你需要在函数中有足够的代码来抵消调用并返回说明 - 几乎总是如此)。这将使代码稍微更慢,因为它需要执行调用和返回指令,但这很可能会被大小减少和代码维护的改进所抵消。
我希望我足够清楚,这似乎有点令人费解:)