Der Precompiler

Der Precompiler ist eine Anwendung, die bisher von Dir unbemerkt vor dem Compiler startete, um Anweisungen des Boardverwalter aus zu führen. Neben speziellem Programmcode, sind es vor allem Anweisungen die Bezeichnungen von GPIO´s und Anweisungen welche speziell an die am Board verbauter Hardware in eine für den Arduino- Compiler verständlichen Code übersetzt.


Auch Du kannst an diesen Anweisungen geben. Üblicherweise werden Anweisungen an diesen, am Anfang eines Sketch geschrieben um sicher zu stellen, dass diese der Precompiler zuerst ausführt. Zudem werden Personen welche mit Dir zusammen arbeiten, Anweisungen an diesen, immer am Anfang des Sketch suchen. Anweisungen an den Precompiler wird ein # Zeichen vorangestellt. Die Anweisung selbst endet mit dem Zeilenende. Ein „;“ ist nicht erforderlich und führt beim Precompiler von „Arduino IDE“ zu einer Fehlermeldung. Demnach ist auch immer nur eine Anweisung pro Zeile erlaubt.

Anweisung: define
Mit der Anweisung define können wir Zeichenfolgen im Sketch ersetzten. So können wir Zeichenfolgen festlegen die in die GPIO- Nummer eines Pins umgewandelt werden. Bereiz bei den 9 GPIO´s des ESP8266 kann dies durchaus nützlich sein. Denn gerade in Projekten mit mehreren Entwicklern muss man sich so nicht immer vergewissern was an dem angesprochenen GPIO angeschlossen werden soll.

Syntax

  • Der Anweisung #define folgt eine Zeichenkette die im Sketch, durch die nachfolgende Zeichenkette zu ersetzen ist.
  • Die Trennung der der Anweisung wie auch der Zeichenketten erfolgt jeweils durch ein Leerzeichen.

Obiges Beispiel zeigt „define“- Anweisungen aus meinem privaten Projekt. Dieses arbeitet mit einem ESP32, dessen GPIO mit ihren jeweiligen Nummern angesprochen werden müssen. Hier ist der Vorteil klar zu erkennen.

Fehler vermeiden!
Die Verwendung von #define ist nicht ganz unproblematisch. Der Precompiler ersetzt jede Textpassage ungeachtet des Kontexts innerhalb des Sketch.

Beispiel wie man es nicht machen sollte:
D4 könnte bei einem „D1 Mini“ auch mit der GPIO- Nummer 2 angesprochen werden. Wir wollen später im Sketch diesen mit der Bezeichnung LedPin ansprechen.
Weiters benutzt das Sketch eine globale Variable mit der Bezeichnung LedPinOut.
Beide Anweisungen sind für sich alleine kein Problem. Doch zusammen in einem Sketch ergibt sich ein Fehler, der nicht sofort offensichtlich ist.

Der Compiler meldet nun einen Fehler in Zeile 2, da ein Variablenname nicht mit einem Buchstaben beginnt.


Lösung
Praktisch alle Programmierer sind daher dazu übergegangen, bei Ersetzungen mittels define grundsätzlich nur Blockbuchstaben zu verwenden. (siehe mein Beispiel!) Das erhöht die Lesbarkeit des Codes. Denn so erkennen Co- Entwickler, dass diese Begriffe durch den Precompiler ersetzt werden und wo sie die Anweisung zur Ersetzung finden werden.
Um einen GPIO in meinem privaten Projekt zu versetzen muss so zum Beispiel nur die Anweisung an den Precompiler geändert werden.
Dies könnte zum Beispiel notwendig werden, wenn ein spezieller GPIO für eine später hinzugefügte Schnittstelle genutzt werden muss, oder aus Platzgründen dieser versetzt werden muss.
Wer sich bei der Vergabe von Variablennamen an den Standard, Groß und Kleinschreibung zu benutzen, kann Konflikte vermeiden.


Konstante const
Natürlich könnte man auch Werte, die immer wieder im Sketch Verwendung finden sollen, mittels define festlegen. Für sogenannte Konstante wird jedoch grundsätzlich davon abgeraten, eine define Anweisung zu verwenden.
Deklariere dazu einfach eine Variable! Wenn Du nun explizit vermeiden möchtest, das Du oder einer deiner Co- Entwickler versehentlich, dieser innerhalb des Sketch einen neuen Wert zuweist, kannst Du dies bereiz bei der Deklaration mit der Anweisung const unterbinden. Der Compiler wird bei einer weiteren Zuweisung den Compiliervorgang abbrechen und eine Fehlermeldung ausgeben.

Der Compiler würde hier einen Fehler in Zeile 2 melden.


Funktionsumfang eines MC´s oder Boards erweitern
Bisher haben wir lediglich Klassen des ESP8266 und unseres „D1 mini“ genutzt, welche fix in der Arduino- Umgebung eingebunden sind. Unsere GPIO´s wie auch die serielle Schnittstelle sind Standardklassen, ohne die ein MC nicht laufen würde und demnach sich die Frage nicht stellt, ob wir diese benötigen. Für komplexere Aufgaben müssen wir jedoch weitere Klassen, welche entweder als sogenannte Librarys zur Verfügung stehen, oder eigene Klassen (dazu kommen wir später) mit einbinden. Dazu nutzen wir die „include“ Anweisung.

Anweisung include

Syntax

  • Der Anweisung #include folgt ein Leerzeichen.
  • Danach geben wir den Namen der sogenannten Header- Datei inklusive der Dateiendung h an.
  • Die Angabe erfolgt je nach Ort der Header- Datei entweder in Anführungszeichen oder zwischen einem Kleiner- und Größer- Zeichen.

Essentielle Librarys eines Boards werden mit dem Boardverwalter mit installiert und werden demnach im Library- Ordner des Boards abgelegt. Diese werden zwischen Größer und Kleiner- Zeichen angegeben.
Selbst installierte, oder selbst erstellte Librarys / Klassen werden im Order „Eigene Dokumente“ abgelegt. Diese werden zwischen Anführungszeichen angegeben.

 

Die WiFi- Klassen des ESP8266 sind Standardklassen des ESP8266 Boardverwalters, welche wir demnach nicht installieren müssen. Jedoch müssen wir diese je nach unserem geplanten Anwendungszweck einbinden. In dem Beispiel oben wollen wir die WiFi- Schnittstelle als Server betreiben. 


Keywords
Viele Librarys sowie Boardverwalter benutzen so genannte Keywords um die Nutzung verständlicher und übersichtlicher zu machen.
So ist es der Precompiler der durch den Boardverwalter angewiesen wird, die Zeichenketten wie HIGH, D4, OUTPUT und viele andere, in eine für den „D1 mini“ richtige Zeichenkette zu ersetzten, die der Compiler versteht. Damit verbessert sich die Lesbarkeit des Codes und man kann im Sketch einprägsame Begriffe verwenden. Sonst müsste man zum Beispiel für jeden GPIO die exakte Speicheradresse wissen.
Auch viele Klassen/Librarys, die wir im nächsten Abschnitt benötigen, machen davon Gebrauch. Da diese Zeichenketten ersetzt werden, kommt es so dazu, dass zu Beispiel ein Vergleich einer integer Variablen mit einer Zeichenkette zustande kommt, bei dem die Zeichenkette nicht in Anführungszeichen steht.
Auch bei der Benutzung von Keywords wird auf die Schreibweise in Blockbuchstaben zurück gegriffen, um Fehler zu vermeiden.
Wir werden auf dieser Seite Keywords grundsätzlich SCHWARZ, FETT UND IN BLOCKBUSCHSTABEN schreiben.


Die Frage nach dem Warum
Solltest Du Dich jetzt fragen, warum nicht alle Klassen des Boardverwalters immer mit eingebunden werden, sehe ich das positiv.
Die Antwort ist jedoch denkbar einfach. Jede Klasse wird vom Compiler als Programm in das hoch zu ladende Programm mit eingebunden. Demnach wird der Compiler immer langsamer und das Programm unnötig aufgeblasen. Auch wenn man die Funktionen/Methoden der Klasse nie benötigt. Der Precompiler weist den Compiler an, eine Klasse immer vollständig mit dem gesamten Programm ein zu binden und für die Variablen der Klasse extra Speicher bereit zu stellen. Dieser kann ja nicht ausschließen, ob das Sketch im Laufe seines Ablaufs darauf zugreifen wird.


Fazit
Neben der Möglichkeit, Code mittels des Precompilers übersichtlicher zu gestallten, ermöglicht uns dieser den Funktionsumfang unseres Boards flexibel zu erweitern. Auch wenn man den Precompiler nicht kennen würde, könnte man ohne weiteres einen MC programmieren und zum laufen bringen. Doch wer weis, was im Hintergrund abläuft, wird sich bei Abbrüchen des Compilers leichter tun, dessen Fehlermeldungen zu interpretieren.
Für Fragen und Anregungen zu diesen Beitrag stehen wir Dir in unserer Google Community zur Verfügung.