Wenn ich diese Skizze für den Yún zusammenstelle:
int led = 7;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
}
Ich bekomme:
Sketch belegt 5.098 Byte (17%) des Programmspeicherplatzes.
Das Maximum liegt bei 28.672 Bytes. Globale Variablen belegen 153 Bytes (5%) des dynamischen Speichers, während für lokale Variablen 2.407 Bytes verbleiben. Maximal sind 2.560 Bytes möglich.
Auch wenn ich die BareMinimum-Skizze kompiliere:
void setup() {
// setup
}
void loop() {
// loop
}
Ich bekomme:
Sketch belegt 4.548 Byte (15%) des Programmspeicherplatzes.
Das Maximum liegt bei 28.672 Bytes. Globale Variablen belegen 151 Byte (5%) des dynamischen Speichers, während für lokale Variablen 2.409 Byte übrig bleiben. Maximal sind 2.560 Bytes möglich.
Warum belegt eine einfache Skizze 15% des zugewiesenen Programmspeicherplatzes? Und warum belegt eine sehr einfache Skizze 17% des Programmspeicherplatzes? Laut der Arduino-Website :
Es ist einfach, alles zu nutzen, indem Sie viele Zeichenfolgen in Ihrem Programm haben. Beispiel: Bei einer Deklaration wie
char message[] = "I support the Cape Wind project.";
folgt werden 33 Bytes in den SRAM geschrieben (jedes Zeichen benötigt ein Byte plus das Abschlusszeichen '\ 0').
In keiner dieser Skizzen sind jedoch Zeichenfolgen deklariert.
Es scheint, als würden sie andere Bibliotheken / Klassen importieren oder verwenden, die ich nicht spezifiziere. Vielleicht importiert es eine Systemstandardbibliothek? Oder ist es etwas anderes?
quelle
Sie haben bereits einige sehr gute Antworten. Ich poste dies nur, um einige Statistiken zu teilen, die ich eines Tages gemacht habe. Ich habe mir die gleichen Fragen gestellt: Was nimmt so viel Platz in einer minimalen Skizze ein? Was ist das Minimum, um die gleiche Funktionalität zu erreichen?
Im Folgenden finden Sie drei Versionen eines minimalen Blinkprogramms, mit dem die LED an Pin 13 jede Sekunde umgeschaltet wird. Alle drei Versionen wurden für ein Uno (ohne USB) mit avr-gcc 4.8.2, avr-libc 1.8.0 und arduino-core 1.0.5 kompiliert (ich verwende die Arduino-IDE nicht).
Erstens, der Standard-Arduino-Weg:
Dies kompiliert auf 1018 Bytes. Bei beiden
avr-nm
und bei der Demontage habe ich diese Größe in einzelne Funktionen unterteilt. Vom größten zum kleinsten:In der obigen Liste ist die erste Spalte die Größe in Bytes und die zweite Spalte gibt an, ob der Code aus der Arduino-Kernbibliothek (A, insgesamt 822 Bytes), der C-Laufzeit (C, 148 Bytes) oder dem Benutzer (U) stammt 48 Bytes).
Wie in dieser Liste zu sehen ist, ist die größte Funktion die Routine, die den Timer 0-Überlaufinterrupt bedient. Diese Routine ist verantwortlich Zeit der Verfolgung und benötigt wird , um durch
millis()
,micros()
unddelay()
. Die zweitgrößte Funktion istinit()
, die die Hardware-Timer für PWM einstellt, den TIMER0_OVF-Interrupt aktiviert und den USART (der vom Bootloader verwendet wurde) trennt. Sowohl diese als auch die vorherige Funktion sind in definiert<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.Als nächstes kommt die C + avr-libc-Version:
Die Aufteilung der einzelnen Größen:
Dies sind 132 Byte für die C-Laufzeit und 26 Byte für den Benutzercode, einschließlich der Inline-Funktion
_delay_ms()
.Es kann angemerkt werden, dass, da dieses Programm keine Interrupts verwendet, die Interruptvektortabelle nicht benötigt wird und regulärer Benutzercode an ihre Stelle gesetzt werden könnte. Die folgende Assembly-Version macht genau das:
Dies ist (mit
avr-gcc -nostdlib
) in nur 14 Bytes zusammengefasst, von denen die meisten verwendet werden, um die Umschaltvorgänge zu verzögern, so dass das Blinken sichtbar ist. Wenn Sie diese Verzögerungsschleife entfernen, erhalten Sie ein 6-Byte-Programm, das zu schnell blinkt, um gesehen zu werden (bei 2 MHz):quelle
Ich schrieb einen Beitrag über Warum braucht man 1000 Bytes, um eine LED zu blinken? .
Die kurze Antwort lautet: "Es dauert nicht 2000 Bytes, um zwei LEDs zu blinken !"
Die längere Antwort ist, dass die Standard-Arduino-Bibliotheken (die Sie nicht verwenden müssen, wenn Sie nicht möchten) einige nette Funktionen haben, um Ihr Leben zu vereinfachen. Beispielsweise können Sie Pins zur Laufzeit nach Nummer adressieren, wobei die Bibliothek Pin 8 in den richtigen Port und die richtige Bitnummer konvertiert. Wenn Sie den Portzugriff fest codieren, können Sie diesen Aufwand sparen.
Selbst wenn Sie sie nicht verwenden, enthalten die Standardbibliotheken Code zum Zählen von "Ticks", sodass Sie die aktuelle "Zeit" (durch Aufrufen
millis()
) herausfinden können . Dazu muss der Overhead einiger Interrupt-Serviceroutinen hinzugefügt werden.Wenn Sie (auf dem Arduino Uno) diese Skizze vereinfachen, wird der Programmspeicher auf 178 Byte (auf IDE 1.0.6) reduziert:
OK, 178 Bytes sind nicht so viel, und davon sind die ersten 104 Bytes die Hardware-Interrupt-Vektoren (jeweils 4 Bytes für 26 Vektoren).
Es sind also nur 74 Bytes erforderlich, um eine LED zu blinken. Und von diesen 74 Bytes sind die meisten wirklich der Code, der vom Compiler generiert wird, um den globalen Speicher zu initialisieren. Wenn Sie genügend Code hinzufügen, um zwei LEDs zu blinken:
Dann erhöht sich die Codegröße auf 186 Bytes. Man könnte also argumentieren, dass es nur
186 - 178 = 8
Bytes braucht, um eine LED zu blinken.Also, 8 Bytes, um eine LED zu blinken. Klingt für mich ziemlich effizient.
Falls Sie versucht sind, dies zu Hause zu versuchen, sollte ich darauf hinweisen, dass der oben angegebene Code zwar zwei LEDs blinkt, dies jedoch sehr schnell geschieht. Tatsächlich blinken sie mit 2 MHz - siehe Screenshot. Kanal 1 (gelb) ist Pin 12, Kanal 2 (cyan) ist Pin 13.
Wie Sie sehen, haben die Ausgangspins eine Rechteckwelle mit einer Frequenz von 2 MHz. Pin 13 ändert den Zustand 62,5 ns (ein Taktzyklus) vor Pin 12 aufgrund der Reihenfolge des Umschaltens der Pins im Code.
Wenn Sie also nicht viel bessere Augen als meine haben, werden Sie tatsächlich keinen blinkenden Effekt sehen.
Als amüsantes Extra können Sie zwei Pins auf der gleichen Programmfläche umschalten wie einen Pin.
Das kompiliert in 178 Bytes.
Dies gibt Ihnen eine höhere Frequenz:
Jetzt sind wir auf 2,66 MHz.
quelle
init()
(wie der normalemain()
Fall ist) , dann die Datei wiring.c (das hatinit
darin) wurde nicht verbunden. Als Ergebnis wird die Verarbeitung für die Interrupt - Handler (fürmillis()
,micros()
etc.) weggelassen wurde. Es ist wahrscheinlich nicht besonders praktisch, es wegzulassen, es sei denn, Sie müssen nie etwas zeitlich festlegen. Fakt ist jedoch, dass die Größe der Skizze von Ihrer Eingabe abhängt. Wenn Sie beispielsweise Seriell verwenden, werden sowohl der Programmspeicher als auch der Arbeitsspeicher betroffen.