Wie man eine Skizze wirklich verkleinert

9

Ich möchte zu Testzwecken eine möglichst kleine Skizze erstellen. Das Problem ist, wenn ich die BareMinimum-Skizze kompiliere (mit einem leeren Setup und einer leeren Schleife), bekomme ich 466 Bytes für das Uno und satte 4.242 für das Leonardo. Gibt es eine Möglichkeit, eigenen Code zu schreiben, der keine zusätzlichen Funktionen hat (nämlich Timer0 für millis()und delay()) ? Ich möchte auch die Tastatur- / Mausfunktionen für den Leonardo deaktivieren können.

Der Doktor
quelle
4
Sollte dies nicht mit Leonardo und nicht mit Uno markiert sein (und sich auf ein Board konzentrieren)? Dies sind separate Fragen.
Asheeshr
Ich möchte nur darauf hinweisen, dass eine leere kompilierte Skizze für viele Boards groß ist, insbesondere für die nativen USB-basierten
TheDoctor
Ich möchte auch die Tastatur- / Mausfunktionen für den Leonardo deaktivieren können. ist die zweite Frage.
Asheeshr

Antworten:

3

Sie sollten in der Lage sein, Ihre eigene Board-Definition mit einer benutzerdefinierten board.txt-Datei gemäß https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification zu erstellen . Wie ich sehe, enthält die Definition des Leonardo mehrere USB-Funktionen. Ich würde hoffen, dass die Kompilierungsaufnahme des 4K auf diesen Flags und nicht auf dem Prozessortyp basiert.

Wo die board.txt den Upload verwenden würde, werden Bootloader-Abschnitte von Leonardo und der Build von Uno verwendet.

Dies alles setzt voraus, dass der Build der Kernbibliothek keine prozessorspezifischen Flags verwendet, um USB-Funktionen einzuschließen.

Wenn Sie solche Arbeit bekommen. post back, ich bin sicher, dass andere daran interessiert wären.


Ich bin kürzlich auf diese 4K-Einschränkung für eine Bibliotheksdemo gestoßen, die die UNO tatsächlich ausgereizt hat und eine einfügen musste

#if !defined(__AVR_ATmega32U4__)
...

um einen großen Teil der zusätzlichen Funktionen in der Skizze, die auf den Leonardo passen.

Ich hatte angenommen (falsch), dass dieses 4K war, weil ich immer noch Serial.print enthielt, das über die CDC des USB auf dem Leo lief. Aber ich sehe nach einem Speicherauszug einer leeren Skizze, dass sie immer noch da sind.

C:\Users\mflaga\AppData\Local\Temp\build8958339595868119500.tmp>avr-objdump -d sketch_feb13a.cpp.elf > sketch_feb13a.cpp.elf.lst

Was Sinn macht. Da der Leonardo weiterhin den USB-CDC-Client (den 4K) benötigt, um die 1200-Baud-Verbindung von AVR-DUDE zu erkennen, um den Remote-Neustart durchzuführen.


Daher muss auch eine benutzerdefinierte Boards.txt ohne USB im Build erstellt werden

leonardo.upload.use_1200bps_touch=true

entfernt.

Nach dem Laden auf das Ziel muss der Upload mit einem manuellen Zurücksetzen des Ziels synchronisiert werden. Da die Fähigkeit zum Remote-Neustart verloren geht.

mpflaga
quelle
aktualisiert, warum 4K noch kompiliert wird, auch wenn Serial.print weggelassen wird.
mpflaga
3

Ich wollte vor kurzem genau das tun. Da es keinen guten Weg gibt, habe ich einen Patch für das Stino Sublime-Text-Arduino-Plugin geschrieben, um genau dies zu tun. Es wurde später akzeptiert, daher sollte es in allen aktuellen Stino-Installationen enthalten sein.

Dies fügt Stino eine neue Option hinzu:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie diesen Modus verwenden, werden folgende Kompilierungsergebnisse erzielt:

Für eine Uno:

Größe der binären Skizze: 172 Byte (von maximal 32256 Byte 0,53 Prozent).
Geschätzte Speichernutzung: 0 Bytes (von maximal 1024 Bytes 0,00 Prozent).

Für einen Leonardo

Größe der binären Skizze: 240 Byte (von maximal 28672 Byte 0,84 Prozent).
Geschätzte Speichernutzung: 0 Byte (maximal 2560 Byte, 0,00 Prozent).

Eigentlich Programmierung den leonardo mit der oben kompilierte Ausgabe ist wahrscheinlich eine schlechte Idee, wie es vielleicht die Auto-Reset - Funktionalität brechen, aber man könnte , wenn man will. Hutspitze an mpflaga, weil er dies in seiner Antwort vermerkt hat.

Beachten Sie, dass die Speicherberichte tatsächlich falsch sind, dies ist jedoch ein separates Problem .

Der oben genannte Code lautet:

int main()
{
    while (1)
    {

    }
}

Einige Notizen:

  • Sie ist nicht eine „Skizze“ mehr schreiben, nicht , dass Sie jemals tatsächlich noch eine Skizze schreiben. Sie schreiben Programme . Zeitraum. Es ist mir egal, was die Arduino-Wackos sagen wollen, sie können Begriffe nicht neu definieren.
  • Das gesamte Interrupt-Management erfolgt manuell. Dies bedeutet nein milis()oder ähnlich.
  • Sie können weiterhin die seriellen Arduino-Bibliotheken usw. verwenden, wenn Sie möchten. Du musst #include <Arduino.h>.
  • Sie definieren main. Du kommst nie zurück von main. Wenn Sie Setup-Sachen wollen, geht es vor dem while (1).
Connor Wolf
quelle
@jfpoilpret Du nennst das eine IDE? Eher wie Notizblock mit Makros ...
Ron
@ Ron-E Ich nenne es keine IDE, Arduino IDE ist sein Name, also habe ich nur seinen Namen verwendet, obwohl es diesen Namen nicht wert ist.
jfpoilpret
2
@FakeName Auf Stack Exchange-Sites ist keine fehlerhafte Sprache zulässig (siehe: stackoverflow.com/help/behavior ). Ich habe es in diesem Fall bearbeitet, aber bitte versuchen Sie in Zukunft, auf dieser Website keine Explosivstoffe mehr zu verwenden. Vielen Dank.
Peter Bloomfield
2

Obwohl dies von Ihrer Skizze abhängt, können Sie die Größe etwas verringern, indem Sie Code mit Methoden wiederverwenden.

Nehmen Sie diesen Code:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  val = digitalRead(10);
}

1.322 Bytes auf Arduino Uno. Lassen Sie es uns jetzt etwas verkleinern:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  for(uint8_t i = 0; i < 8; i++) {
    blink(HIGH);
    blink(LOW);
  }    
  val = digitalRead(10);
}

void blink(uint8_t state) {
  digitalWrite(led, state);   // turn the LED to the right state
  delay(1000);                // wait for a second
}

1.194 Bytes. Das sind ungefähr 10% weniger!

Obwohl es eine Skizze nicht stark verkleinert, kann es manchmal die einfachste Route sein, wenn Sie zwei Bytes über dem Grenzwert liegen oder zunächst nur eine kompaktere Skizze erstellen möchten, ohne die Funktionalität zu verlieren. Es ist nicht für jede Situation geeignet, aber ich finde es manchmal nützlich.

Anonymer Pinguin
quelle
Wenn Sie Code in Funktionen ziehen, erledigt der Compiler im Allgemeinen die harte Arbeit und erledigt den Rest für Sie.
Cybergibbons
@Cybergibbons Können Sie das definieren [für Benutzer, die damit nicht vertraut sind]?
Anonymer Pinguin
3
Wenn Sie Code in eine Funktion aufteilen und diese nicht effizient ist, wird sie vom Compiler im Allgemeinen für Sie eingebunden. Ein Compiler wird jedoch niemals Code in Funktionen aufteilen. Daher ist es fast immer besser, mehr Funktionen zu schreiben.
Cybergibbons
1
Das Einfügen des Codes in Funktionen erleichtert das Lesen und Verstehen
Bei direktem Portzugriff wird die Größe auf 646 Byte verringert. Wenn nur avr-libc (kein Arduino-Kern) verwendet wird, werden 220 Bytes benötigt.
Edgar Bonet
0

@annonomus Pinguin, sicher können wir Obwohl der Code in 1180 Bytes Flash + 13 Bytes RAM für ein Uno auf meinem Computer kompiliert wird, können wir es verbessern :) Also Golf Herausforderung angenommen und auch ein paar nützliche Tipps, da wir im Geschäft von sind Lernen.

Schritt 1: Verringern Sie die variablen Anforderungen. Die Verwendung eines int für einen LED-Port scheint etwas übertrieben, wir haben sicherlich keine 65535 adressierbaren E / A-Ports auf dem Arduino :) Also ändern wir es nur zum Spaß in ein Byte. Wir werden es später auf #define umstellen, aber um die Auswirkungen der Verwendung zu großer Variablentypen zu zeigen.

byte led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Kompiliert in 1172 Bytes + 13 Bytes RAM. Dies spart 8 Byte Flash, da weniger Operationen für das Byte anstelle einer Ganzzahl erforderlich sind. Ich würde 12 Bytes RAM erwarten, aber okay. Nicht so viel, aber jedes gespeicherte Byte ist gut.

Schritt 2: Ändern Sie die Variable in definiert, wann es sinnvoll ist. Zum Beispiel wird das LED-Byte nicht benötigt, der Pin löst sich nicht von selbst.

#define LED 13
int val;

void setup() {                
  pinMode(LED, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Kompiliert in 1142 Bytesflash + 11 Bytes RAM. Bereits 38 Bytes gespeichert. Dies ist auf weniger Registeroperationen zurückzuführen, die zum Abrufen des int-Werts erforderlich sind. Außerdem haben wir 2 Bytes aus dem RAM gespeichert. (Ich frage mich immer noch, warum das Byte nicht zu 1 Byte RAM weniger kompiliert wurde .....)

Schritt 3: Code optimieren. Ich sehe 2 Verzögerungen. Ich frage mich, ob ich es auf 1 Verzögerung ändere, um Platz zu sparen, aber ich muss den Wert des LED-Pins herausfinden und ihn umschalten (umkehren). Wir können das mit digitalRead () machen, aber wird es Platz sparen?

#define LED 13
int val;
void setup() {                
  pinMode(LED, OUTPUT);     
}
void loop() {
  blink();
  val = digitalRead(10);
}
void blink() {
  digitalWrite(LED, !digitalRead(LED));   // toggle the led based on read value
  delay(1000);               // wait for a second and spare yourself the other delay
}

Kompiliert in 1134 Bytes + 11 Bytes RAM. Yay! weitere 8 Bytes. Das ergibt insgesamt 46 Bytes und 2 Codezeilen weniger.

Auch ein weiterer allgemeiner Tipp zum Verringern der Codegröße. Verwenden Sie nicht die String-Klasse. Es ist RIESIG, lernen Sie, wie man mit char-Arrays umgeht, strcpy (), strcmp (). Wenn Sie nur einige grundlegende Zeichenfolgenoperationen haben, verschwendet die Verwendung der Zeichenfolgenklasse meist nur Speicherplatz auf Flash und RAM.

Patrick Deelman
quelle