Abschnitt 2.3, „Die erste Applikation“

Stellen Sie zuerst sicher, dass Sie das ESP-IDF installiert haben (ist im Beitrag ESP-IDF Installation (Windows) | Ein erstes Projekt erstellen beschrieben) und starten Sie die integrierte Entwicklungsumgebung Espressif IDE.

Wählen Sie File – New – ESP IDF Project:

Es wird ein Wizard geöffnet, in dem Sie einen beliebigen Projektnamen eingeben können. Dieser Name wird im Anschluss durch den Namen der Demoapplikation ersetzt.

Drücken Sie „Next“ und wählen Sie das Beispiel hello_world aus. Dafür muss „Create a project using one of the templates“ angehakt und das Projekt angeklickt werden.

„Finish“ erzeugt das Projekt.

Führen Sie nun einen Build des Projekts aus und starten Sie die Applikation, wie im Beitrag ESP-IDF Installation (Windows) | Ein erstes Projekt erstellen beschrieben.

Abschnitt 8.2, FlexiPlot für die Darstellung von Daten verwenden

FlexiPlot ist ein angenehmes Werkzeug zur Darstellung von Daten. Im Entwicklungsprozess ist es, wie auch in Kapitel 8.2, oft notwendig, sich ein Bild der Daten zu machen, um Trends festzustellen oder die Arbeitsweise der Datenverarbeitung mit Filtern zu visualisieren.

Besonders die einfache Verwendung machen FlexiPlot interessant. Nach dem Start erhält man eine Oberfläche, auf der man mit „Add Line Graph“ oder „Add Bar Graph“ Fenster für die beiden Graphentypen öffnen kann. Im „Settings“-Tab eines Graphen stellt man das visuelle Erscheinungsbild sowie den Namen der zugehörigen Daten ein.

Für Abb. 8.4 des Buchs wurde ein Liniengraph mit der ID P0 hinzugefügt. Als „Title“ wurde „ADC Voltage“, als „Name of X Axis“ „Zeit“, als „Name of Y Axis“ „mV“ gesetzt. Der Typ ist ein „Time Plot“. Wird das Tool mit dem seriellen Port des ESP32-C3 verbunden, wird dessen Ausgabe direkt im Graph angezeigt.

Das Beispiel servocontrol schreibt in der Codezeile

printf("{P0|RAW|0,255,0|%d|FIR2|0,0,255|%0.1f|FIR10|200,0,0|%0.1f|IIR|130,130,0|%0.1f}\n", voltage_mV, firValue_2, firValue_10, iirValue);

in den Graphen P0 die drei Einträge für voltage_mv, firValue_2, firValue_10 und iirValue (im Buch aus Übersichtlichkeitsgründen nicht iirValue). Ein Eintrag besteht aus einem Namen, beispielweise RAW, einer RGB-Farbe für die Darstellungen und dem Wert.

Im Beispiel Servocontrol werden zusätzlich die Graphen P1 und P2 verwendet, um den berechneten Widerstandswert und die berechnete Helligkeit anzuzeigen. Die Einstellungen für FlexiPlot sind dem Code des Beispiels im Verzeichnis flexiplot (servocontrol.dash) angefügt.

Über weitere Möglichkeiten des Werkzeugs gibt dessen Webseite Auskunft.

Buchprojekt Pulsoximeter

Poxi und Poxi2

Poxi

Poxi misst den Puls live

esp-dsp-Bibltiothek

Damit die esp-dsp-Bibliothek kompiliert werden kann, muss die in der Datei idf_component.yml im Verzeichnis main als dependency angegeben werden:

espressif/esp-dsp: "^1.2.0"

Außerdem kompiliert die Bibliothek in V 5.0 des ESP-IDF nicht mehr direkt. Zur Behebung kann der Compiler-Fehler in der Datei CMakeLists.txt im Projektverzeichnis abgeschaltet werden:

idf_component_get_property(lib espressif__esp-dsp COMPONENT_LIB)
target_compile_options(${lib} PRIVATE -Wno-error=format)

http://10.0.0.86/pulse

Poxi2

Poxi2 misst Puls und Sauerstoffstättigung mittels „Biometric Hub“

Abschnitt 8, „Analoge Werte verarbeiten“, Applikation servocontrol

Die Applikation servocontrol verwendet ein Potentiometer (mit 10 kOhm) und ein handelsübliches Modellbauservo: Über ein Drehen des Potentiometers wird die Helligkeit der LED und die Stellung des Servos verändert, wie im folgenden Video gezeigt.

Das Beispiel dient als Referenzimplementierung der Kapitel

  • Kapitel 8.1.3, „Messen am Spannungsteiler“
  • Kapitel 8.2, „Werte filtern“
  • Kapitel 8.5.4, „Pulsweitenmodulation (PWM)“

Schaltungsaufbau

Schaltungsaufbau am Steckbrett

Das Potentiometer links ist wie in Kapitel 8.1.3 besprochen über einen Spannungsteiler versorgt. Es wird GPIO2 als ADC-Eingang verwendet. Der Anschluss des Servos ist in Kapitel 8.5.4 mit der „Level Conversion“ durch den Transistor beschrieben. Als Pull-Up wird ein 10 kOhm-Widerstand verwendet, eine Strombegrenzung vom Ausgang GPIO3 zur Basis des Schalttransistors übernimmt ein 1 kOhm-Widerstand.

Schaltungsaufbau auf eine Lochrasterplatine gelötet

Sourcecode

components/ringbuffer

enthält die Implementierung eines Ringpuffers als abstrakter Datentyp, wie er in Kapitel 8.2.1 beschrieben wird.

components/filter

enthält Implementierungen eines allgemeinen Filters mit den polymorphen „Unterklassen“ FIRFilter und IIRFilter, wie er in Kapitel 8.2.1 beschrieben wird.

main

baut auf dem ADC-Beispiel des ESP-IDF auf. Kanal 2 von ADC 1, der auf GPIO 2 geleitet ist, wird in der Hauptschleife zyklisch mit einer Periode von 50 ms ausgelesen und in drei Filter, nämlich einen moving average FIRFilter 2. Ordnung, einen moving averge FIRFilter 10. Ordnung und einen IIRFilter 2. Ordnung geleitet. Über die Einstellung „use filter for servo control“ in der „servocontrol Configuration“ kann gewählt werden, welche Filterausgabe anschließend zum Stellen des Servos (und der LED-Helligkeit) verwendet wird.

Die Filterwerte werden per printf() auf der Konsole ausgegeben. Es ist nun möglich, die Daten per FlexiPlot auszuwerten (siehe Kapitel 8.2).

Abschnitt 8.5.1, „Timer des ESP32-C3“, Applikation gameoflife

Bei Conways Game of Life handelt es sich um ein Spiel basierend auf einem zweidimensionalen zellulären Automaten (siehe Game of Life).

Basierend auf einfachen Regeln der Nachbarschaft pflanzen sich Zellen in der nächsten Generation fort, stirbt ab oder vermehrt sich. So können Populationen beobachtet werden.

Die Implementierung auf dem ESP32-C3 verwendet ein Entwicklerboard mit einer 5×5 LED-Matrix. Zellen, die neu entstehen, leuchten blau. Absterbende Zellen leuchten rot, und fortbestehende grün.

Conways Game of Life auf einem Board mit 5×5 LEDs

Die in main.c untergebrachte Implementierung erzeugt mit generateGame() ein neues Zellenmuster. In der Konfiguration ist einstellbar, ob das Spielfeld zufällig (CONFIG_INITIALIZE_GAMEFIELD_RANDOM), mit einem oszillierenden Objekt (CONFIG_INITIALIZE_GAMEFIELD_OSCILLATING) oder einem Gleiter-Objekt (CONFIG_INITIALIZE_GAMEFIELD_GLIDER) initialisiert wird.

Konfigurierung der Spielfeld-Initialisierung

In der Hauptschleife wird alle 10 ms das aktuelle Spielfeld, falls verändert, an die WS2812-LEDs gesendet. Ein Timer ruft alle 20 ms die Funktion displayGameState() auf, die die Pixel „zeichnet“: blaue Pixel werden schrittweise langsam heller, rote schrittweise dunkler. Bei jedem 50. Aufruf (i.e. jede Sekunde) wird die Funktion calculateGeneration() aufgerufen, um eine neue Generation auf einem dynamisch neu erstellten Spielfeld aus der bestehenden Generation abzuleiten.

Da das Spielfeld mit 5×5 Zellen recht klein ist, sind der linke und der rechte Rand, sowie der obere und der untere Rand direkt benachbart. Links benachbart zu einem Pixel in der linksten Spalte ist also beispielsweise ein Pixel in der rechtesten Spalte.