Labortagebuch - Arduino - Raspberry Pi
14.01.2026 - ESP32 - SD-Card - Data Logger - DS18B20
1. Speicherung auf einer SD-Card
2. ESP32 - graphische Darstellung mit Processing 4
3. ESP32 - graphische Darstellung mit Python/Matplotlib
1. ESP32 - Speicherung auf einer SD-Card
Um die Temperaturwerte über einen längeren Zeitraum zu bearbeiten, werden diese über einen längeren Zeitraum erfasst und auf einer Micro-SD-Card gespeichert. Dazu werden als erstes die Grundlagen für die Speicherung und Auswertung mit Hilfe einer Micro-Sd-Karte dargestellt.
Pin-Bezeichnung
Vorder- und Rückseite des Micro-SD-Card-Moduls
Die Verkabelung
SD-Card-Modul ESP32
VCC VIN(5V)
GND GND
CS GPIO 5
SCK GPIO 18
MISO GPIO 19
MOSI GPIO 23
Das erste Programm schreibt Daten in eine Datei mit dem Dateinamen esp32.txt und gibt die Daten über den seriellen Monitor aus.
Achtung:Vor dem Dateinamen muss ein / (Slash) eingefügt werden

#include <SD.h >
#define PIN_SPI_CS 5 // ESP32 pin GPIO5
File myFile;
void setup() {
Serial.begin(115200);
if (!SD.begin(PIN_SPI_CS)) {
while (1) { Serial.println(F("SD CARD FAILED, OR NOT PRESENT!"));
delay(1000); } }
Serial.println(F("SD CARD INITIALIZED."));
// Datei öffnen zum Schreiben
myFile = SD.open("/esp32.txt", FILE_WRITE);
if (myFile) {
myFile.println("ESP32"); // Schreibe den Text ESP32
myFile.println("SD-Card Beispiel"); // Schreibe eine weitere Zeile in die Datei
myFile.close(); } else {
Serial.print(F("SD Card: Beim Versuch, die Datei zu öffnen, ist ein Problem aufgetreten esp32.txt")); }
// Datei zum Lesen öffnen
myFile = SD.open("/esp32.txt", FILE_READ);
if (myFile) {
while (myFile.available()) {
char ch = myFile.read(); // Es werden die Buchstaben einer nach dem andern gelesen
Serial.print(ch); // Die Buchstaben werden im seriellen Monitor geschrieben
}
myFile.close();// Die Datei wird geschlossen
} else {Serial.print(F("SD Card: Beim Versuch, die Datei zu öffnen, ist ein Problem aufgetreten esp32.txt")); } }
void loop() {}
Arduino-Sketch zur SD-Card: Write/Read
Für die Programmierung des ESP32 mit der Arduino-IDE gibt es eine Reihe von Befehlen, mit denen man auf die Micro-SD-Card zugreifen kann. Als Ausgangslage sind folgende Vereinbarungen vorausgesetzt:
#include <SD.h >
#define PIN_SPI_CS 5 // ESP32 pin GPIO5
File myFile;

Folgende Befehle sind verfügbar:
1. Datei öffnen
myFile = SD.open("/test.txt");

2. Datei im Schreibmodus öffnen
myFile = SD.open("/test.txt", FILE_WRITE);

3. Datei schließen
myFile.close();

4. In die Datei schreiben
myFile.println("Hallo");
myFile.print("Wert: ");
myFile.println(123);

5. Datei lesen
while (myFile.available()) {
Serial.write(myFile.read());}
Oder zeilenweise:
String line = myFile.readStringUntil('\n');

6. Datei löschen
SD.remove("/test.txt");

7. Ordner erstellen
SD.mkdir("/daten");

8. Ordner löschen
SD.rmdir("/daten");

9. Dateigröße abfragen
Serial.println(file.size());

10. Prüfen, ob Datei existiert
if (SD.exists("/test.txt")) {
Serial.println("Datei existiert");}

Im folgenden werden einige Programme zusammengestellt, die für die Programmierung der SD-Card nützlich seine können.
1. Programm, das alle Dateien auf der vorhandenen SD-Card auflistet.

#include <FS.h >
#include <SPI.h >
#include <SD.h >
void listFiles(const char *dirname, uint8_t levels) {
File root = SD.open(dirname);
if (!root) { Serial.println("Fehler beim Öffnen"); return; }
if (!root.isDirectory()) return;
File file = root.openNextFile();
while (file) {
Serial.println(file.name());
file = root.openNextFile(); }
}
void setup() {
Serial.begin(115200);
SD.begin(5); // je nach SD-Adapter
listFiles("/", 0);}
void loop() {}

Arduino-Sketch: Ausgabe aller vorhandenen Dateien
Hier ist die Ausgabe im seriellen Monitor:

mode:DIO, clock div:1
load:0x3fff0030,len:4916
load:0x40078000,len:16436
load:0x40080400,len:4
ho 8 tail 4 room 4
load:0x40080404,len:3524
entry 0x400805b8
random_log.csv
random_10.csv
numbers.txt
random_numbers.txt
temp_log.csv
zufallszahlen.txt
zahlen.csv
zahlen_mit_timestamp.csv
temperatur_log.csv
temperatur.csv
2. Programm, das die Daten einer bekannten Datei im seriellen Monitor ausgibt.

#include <SPI.h >
#include <SD.h >
// CS-Pin der SD-Karte (anpassen je nach Modul!)
const int chipSelect = 5;
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.println("Initialisiere SD-Karte...");
if (!SD.begin(chipSelect)) {
Serial.println("Fehler: SD-Karte konnte nicht initialisiert werden.");
return;}
Serial.println("SD-Karte erkannt.");
// Datei Öffnen
File file = SD.open("/Zufallszahlen.txt");
if (!file) {
Serial.println("Fehler: Datei '/Zufallszahlen.txt' konnte nicht geöffnet werden.");
return;}
Serial.println("\nInhalt von /zufallszahlen.txt:\n");
// Datei zeilenweise ausgeben
while (file.available()) {
String line = file.readStringUntil('\n');
Serial.println(line); }
file.close();
Serial.println("\nDatei wurde vollständig gelesen.");}
void loop() { }

Arduino-Sketch: Ausgabe einer bekannten Datei im ser. Monitor
Hier ist die Ausgabe im seriellen Monitor:

63
9
38
73
34
2
30
54
67
84
Datei wurde vollständig gelesen.
3. Programm, mit dem 10 Zufallszahlen gespeichert werden und dann im seriellen Monitor ausgegeben werden

#include <SPI.h >
#include <SD.h >
const int chipSelect = 5; // Beispiel für CS-Pin (anpassen, je nach Verbindung)
void setup() {
Serial.begin(115200);
while (!Serial) { } // Warten, bis serieller Monitor bereit ist
Serial.println("SD-Karteninitialisierung...");
if (!SD.begin(chipSelect)) { Serial.println("SD-Karte erkannt.");
File file = SD.open("/zahlen.txt", FILE_WRITE);
if (!file) {
Serial.println("Fehler beim Öffnen der Datei zum Schreiben.");
return; }
Serial.println("Zufallszahlen werden gespeichert...");
randomSeed(analogRead(0)); // Initialisierung des Zufallsgenerators
for (int i = 0; i < 10; i++) {
int zahl = random(0, 100); // Zufallszahl zwischen 0 und 99
file.println(zahl); } file.close();
Serial.println("Zahlen wurden gespeichert.\n");
// Jetzt lesen wir die Datei und geben sie im seriellen Monitor aus
file = SD.open("/zahlen.txt");
if (!file) {
Serial.println("Fehler beim Öffnen der Datei zum Lesen.");
return; }
Serial.println("Inhalt von /zahlen.txt:");
while (file.available()) {
Serial.write(file.read()); }
file.close();}
void loop() {}

Arduino-Sketch: Speichern von 10 Zufallszahlen und Ausgabe im ser. Monitor
Hier ist die Ausgabe im seriellen Monitor:

Zufallszahlen:
26
73
98
36
49
81
65
36
14
21
4. Programm, mit dem 10 Zufallszahlen in einer CSV-Datei gespeichert werden und dann im seriellen Monitor ausgegeben werden

#include <SPI.h >
#include <SD.h >
const int chipSelect = 5; // Anpassen je nach deinem SD-Modul
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.println("Initialisiere SD-Karte...");
if (!SD.begin(chipSelect)) { return;}
Serial.println("SD-Karte erkannt.");
// Datei zum Schreiben Öffnen (wird überschrieben) Serial.println("Fehler beim Öffnen der Datei zum Schreiben.");
return;}
Serial.println("Schreibe Zufallszahlen in zahlen.csv...");
// Überschrift (optional)
file.println("Index,Zahl");
// Zufallszahlen erzeugen und schreiben
randomSeed(analogRead(0)); // Zufallsgenerator initialisieren
for (int i = 0; i < 10; i++) {
int zahl = random(0, 100); // Zahl von 0 bis 99
file.print(i);
file.print(",");
file.println(zahl);}
file.close();
Serial.println("Zahlen wurden gespeichert.\n");
// Datei öffnen und auslesen
file = SD.open("/zahlen.csv");
if (!file) {
Serial.println("Fehler beim Öffnen der Datei zum Lesen.");
return;}
Serial.println("Inhalt von zahlen.csv:");
while (file.available()) {
Serial.write(file.read());}
file.close();}
void loop() {}

Arduino-Sketch: Speichern von 10 Zufallszahlen in einer CSV-Datei
Eine CSV-Datei (Comma-Separated Values) ist eine einfache Textdatei, die tabellarische Daten speichert, wobei Werte durch ein Trennzeichen (meist ein Komma, oft auch ein Semikolon) getrennt sind, wodurch sie sich ideal zum Austausch von Daten zwischen verschiedenen Programmen wie Tabellenkalkulationen (Excel, Google Sheets) oder Datenbanken eignet.
Textdatei: Es ist eine reine Textdatei, die von fast jedem Programm gelesen werden kann.
Struktur: Jede Zeile ist ein Datensatz, und die Spalten (Felder) werden durch ein Zeichen getrennt.
Dateiendung: .csv.

Hier ist die Ausgabe im seriellen Monitor:

Initialisiere SD-Karte... Schreibe Zufallszahlen in zahlen.csv...
Zahlen wurden gespeichert.

Inhalt von zahlen.csv:
Index,Zahl
0,60
1,96
2,30
3,69
4,17
5,50
6,35
7,17
8,87
9,28
5. Programm, mit dem 10 Zufallszahlen mit einem sog. timestamp in einer CSV-Datei gespeichert werden und dann im seriellen Monitor ausgegeben werden

#include <SPI.h >
#include <SD.h >
#include < WiFi.h >
#include < time.h >
// WLAN-Zugangsdaten
const char* ssid = "WLAN-PDGCKM";
const char* password = "4535897740339072";
const int chipSelect = 5;// SD-Karten CS-Pin (anpassen!)
// NTP-Zeiteinstellungen
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600; // MEZ = +1 Stunde
const int daylightOffset_sec = 3600; // Sommerzeit = +1h
void setup() {
Serial.begin(115200);
while (!Serial) {}
// WLAN verbinden
Serial.printf("Verbinde mit WLAN: %s\n", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");}
Serial.println("\nWLAN verbunden.");
// Zeit synchronisieren
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Zeit konnte nicht synchronisiert werden.");
return; }
Serial.println("Zeit synchronisiert.");
// SD-Karte initialisieren
Serial.println("Initialisiere SD-Karte...");
if (!SD.begin(chipSelect)) {
Serial.println("SD-Karte konnte nicht initialisiert werden.");
return; }
Serial.println("SD-Karte bereit.");
// Datei Öffnen (überschreibt bestehende Datei)
File file = SD.open("/zahlen_mit_timestamp.csv", FILE_WRITE);
if (!file) {
Serial.println("Fehler beim Öffnen der Datei zum Schreiben.");
return; }
// CSV-Header schreiben
file.println("Zeit,Zufallszahl");
randomSeed(analogRead(0)); // Zufall initialisieren
// 10 Zufallszahlen erzeugen und mit Zeitstempel speichern
for (int i = 0; i < 10; i++) {
int zahl = random(0, 100); // Zufallszahl 0 bis 99
// Aktuelle Zeit holen
if (!getLocalTime(&timeinfo)) {
Serial.println("Fehler beim Holen der Uhrzeit.");
continue; }
// Zeitformat erstellen
char timeString[20];
strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", &timeinfo);
// In Datei schreiben
file.print(timeString);
file.print(",");
file.println(zahl);
delay(1000); }
file.close();
Serial.println("Zahlen wurden gespeichert.\n");
// Datei Öffnen zum Lesen
file = SD.open("/zahlen_mit_timestamp.csv");
if (!file) {
Serial.println("Fehler beim Öffnen der Datei zum Lesen.");
return;}
Serial.println("Inhalt von zahlen_mit_timestamp.csv:");
while (file.available()) {
Serial.write(file.read()); } file.close();}
void loop() {}

Arduino-Sketch: Speichern von 10 Zufallszahlen in einer CSV-Datei
Hier ist die Ausgabe im seriellen Monitor:

Verbinde mit WLAN: WLAN-PDGCKM
..........
WLAN verbunden.
Zeit synchronisiert.
Initialisiere SD-Karte...
SD-Karte bereit.
Zahlen wurden gespeichert.

Inhalt von zahlen_mit_timestamp.csv:
Zeit,Zufallszahl
2026-01-04 18:32:54,75
2026-01-04 18:32:55,53
2026-01-04 18:32:56,3
2026-01-04 18:32:57,13
2026-01-04 18:32:58,97
2026-01-04 18:32:59,23
2026-01-04 18:33:00,19
2026-01-04 18:33:01,23
2026-01-04 18:33:02,75
2026-01-04 18:33:03,36
2. ESP32 - graphische Darstellung mit Processing 4
Im folgenden Teil werden die auf einer SD-Card gespeicherten Daten mit der Processing-4-IDE graphisch dargestellt. Dazu gibt es zwei Möglichkeiten:
1. Die SD-Card wird in einen SD-Card-Reader gesteckt und der Zugriff erfolgt vom Processing-4-Programm direkt auf die Datei. Man benötigt also keinen Sketch in der Arduino-IDE.
2. Die Datei wird über die Arduino-IDE in der seriellen Schnittstelle geöffnet und über diese Schnittstelle hat das Processing-Programm Zugriff auf die Daten.
Bevor damit begonnen wird, sollen noch einige sinnvolle Befehle in der Processing-IDE angegeben werden.
Manchmal ist es sinnvoll, eine andere Schriftart zu benutzen. Dazu ist es hilfreich, zu wissen, welche Schriftarten überhaupt zur Verfügung stehen. Denn bei der Benutzung der Schriftarten ist es wichtig, den Namen genau zu wissen, da nur der richtige Eintrag akzeptiert wird. Nachfolgend der Processing-Code:
void setup() {
String[] fonts = PFont.list();
printArray(fonts);
}


Mit diesem Programm werden alle verfügbaren Schriftarten ausgedruckt und zwar im unteren Ausgabefeld der Processing-IDE. Benutztwurde Processing 4 mit der Hardware Raspberry Pi 5 und dem OS bookworm-64 Bit. Es sind sehr viele Schriftarten verfügbar – ungefähr 500.

Es folgt ein Programm, mit dem man einen Text mit einer angegebenen Schriftart ausgibt und dieses Fenster als Bilddatei abspeichert. Diese Bilddatei wird in dem Ordner gespeichert, indem der Processing-Code abgelegt ist.

PFont font;
void setup() {
font =createFont("Noto Serif SemiCondensed Bold",26);
textFont(font);
// ab jetzt erfolgt die Ausgabe mit der vereinbarten Schriftart
}
void draw() {
background(255);
fill(0);
text("Hallo Processing!", 50, 100);
saveFrame("bild_font.png");
// speichert im Sketch-Ordner. Der Name der Bilddatei ist frei wählbar.
noLoop();}



Achtung: Die Schriftarten variieren je nach Betriebssystem. So ist z.B. Arial unter dem OS-bookworm beim Rasberry Pi nicht verfügbar.
Jetzt kommen wir zur graphischen Darstellung einer CSV-Datei mit Hilfe der Processing 4 - IDE. Die CSV-Datei muss dabei im Unterordner data des Sketch-Ordners liegen, in dem der Processing-Sketch gespeichert wurde. Hier muss man auf folgendes achten: der Sketch-Ordner wird erst dann erzeugt, wenn Processsing geschlossen wird. Dann muss der Code abgespeichert werden. Also muss man, bevor man das Programm ausführt, erst einmal abspeichern. Jetzt ist der Ordner bekannt. Man verzweigt dahin und erzeugt ein Verzeichnis data. In dieses kopiert man die CSV-Datei, die man benutzen will.

Processing-Code
Table table;
float[] values;
String[] timestamps;
PFont myFont;
void setup() {
size(1000, 600);
background(255);
myFont=createFont("Arial",16);
table = loadTable("zahlen_mit_timestamp.csv", "header");
int rowCount = table.getRowCount();
values = new float[rowCount];
timestamps = new String[rowCount];
for (int i = 0; i < rowCount; i++) {
TableRow row = table.getRow(i);
values[i] = row.getFloat("Zufallszahl");
timestamps[i] = row.getString("Zeit");
}
drawGraph();}
void drawGraph() {
float margin = 80;
float graphWidth = width - 2 * margin;
float graphHeight = height - 2 * margin;
// Skalierung
float minValue = min(values);
float maxValue = max(values);
// Achsen zeichnen
stroke(0);
strokeWeight(1);
line(margin, margin, margin, height - margin); // Y-Achse
line(margin, height - margin, width - margin, height - margin); // X-Achse
// Achsenbeschriftung
fill(0);
textAlign(CENTER);
//textSize(14);
textFont(myFont);
text("Zeit", width / 2, height - 30);
pushMatrix();
translate(30, height / 2);
rotate(-HALF_PI);
text("Wert", 0, 0);
popMatrix();
// Y-Achse Skalierung
int yTicks = 5;
for (int i = 0; i <= yTicks; i++) {
float y = map(i, 0, yTicks, height - margin, margin);
float valueLabel = map(i, 0, yTicks, minValue, maxValue);
stroke(200);
line(margin, y, width - margin, y); // horizontale Hilfslinien
fill(0);
textAlign(RIGHT, CENTER);
text(nf(valueLabel, 1, 1), margin - 10, y); }
// Datenpunkte & Linien zeichnen
float xSpacing = graphWidth / (values.length - 1);
stroke(50, 100, 250);
strokeWeight(2);// Dicke des Graphen wird vereinbart
noFill();
beginShape();
for (int i = 0; i < values.length; i++) {
float x = margin + i * xSpacing;
float y = map(values[i], minValue, maxValue, height - margin, margin);
vertex(x, y); }
endShape();
// X-Achse Beschriftungen (alle n-ten Zeitstempel)
int xLabelStep = max(1, values.length / 10); // max 10 Labels
textSize(9);
textAlign(CENTER, TOP);
for (int i = 0; i < values.length; i += xLabelStep) {
float x = margin + i * xSpacing;
text(timestamps[i], x, height - margin + 5); }
saveFrame("Graph_CSV_Datei.png"); // speichert im Sketch-Ordner
noLoop();}
Processing-Code für graphische Darstellung einer CSV-Datei
Graphische Ausgabe der Daten von einer SD-Card mit Hilfe von Processing 4 über die serielle Schnittstelle
Im folgenden Abschnitt werden die erhobenen Daten, die auf einer SD-Card gespeichert wurden, in der Processing-IDE graphische dargestellt. Der Zugriff auf die vorhandenen Daten geschieht über die serielle Schnittstelle. Man braucht also die CSV-Datei nicht in den Ordner des Sketch-Programms der Processing-IDE zu verschieben.

Als erstes müssen mit einem Arduino-Sketch die Daten über die serielle Schnittstelle für andere Programme (hier: Processing 4) zugänglich gemacht werden. Dies geschieht mit folgendem kurzen Programm.

Arduino-Sketch

#include <SPI.h >
#include <SD.h >
// CS-Pin der SD-Karte (anpassen je nach Modul!)
const int chipSelect = 5;
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.println("Initialisiere SD-Karte...");
if (!SD.begin(chipSelect)) {
Serial.println("Fehler: SD-Karte konnte nicht initialisiert werden.");
return;}
Serial.println("SD-Karte erkannt.");
// Datei öffnen
File file = SD.open("/zufall.csv");
if (!file) {
Serial.println("Fehler: Datei '/zufall.csv' konnte nicht geöffnet werden.");
return;}
Serial.println("\nInhalt von /zufall.csv:\n");
// Datei zeilenweise ausgeben
while (file.available()) {
String line = file.readStringUntil('\n');
Serial.println(line);
delay(100);}
file.close();
Serial.println("\nDatei wurde vollständig gelesen.");}
void loop() {}

Dieser Sketch muss jetzt hochgeladen werden, damit die Daten mit Hilfe der seriellen Schnittstelle zur Verfügung gestellt werden können. Zur Kontrolle kann jetzt in den seriellen Monitor geschaltet werden. Dazu sollte der Reset-Button am ESP32 gedrückt werden. Wenn danach der Processing-Code gestartet wird, muss der serielle Monitor geschlossen werden, um den Port für den Processing-Code freizugeben.

Die beiden Sketche können hier heruntergeladen werden.
Arduino-Sketch: Daten in die serielle Schnittstelle
Processing-Sketch: Graphische Darstellung der Daten einer CSV-Datei auf einer SD-Card


Die Angaben für die Zeitangabe (Beispiel: 2026-01-04 18:32:54)sind sehr lang, so dass die einzelnen Werte sich überschneiden. Bei kürzerem Text für die Zeitangabe, z.B. 1, 2, 3 usw., ist dies kein Problem. Bei dieser Länge jedoch würde man die Beschriftung besser um 90 Grad drehen, also eine senkrechte Beschriftung angeben.

Hinweis für die Darstellung in Processing 4: Die Dicke der Linie des Graphen kann man mit folgendem Befehl verändern: strokeWeight(4);- je größer der Zahlenwert je dicker die Linie. Auch die Farbe des Graphen kann man ändern: stroke(100, 100, 250); - Angabe im RGB-Modus.
Die erzeugt Grafik man man seperat als Bilddatei mit folgendem Befehl abspeichern: saveFrame("Graph_CSV_Datei.png"); - die Datei wird im Ordner der Sketch-Datei abgespeichert.
Processing-Sketch
import processing.serial.*;
PFont font;
Serial myPort;
ArrayList temps = new ArrayList();
ArrayList times = new ArrayList(); // Zeit als String
int margin = 50;
void setup() {
size(1000, 600);
background(255);
font =createFont( "Noto Serif SemiCondensed Medium",26);
textFont(font);
println(Serial.list());
myPort = new Serial(this, "/dev/ttyUSB0", 115200);
// Unter Windows COM-Port eintragen
myPort.bufferUntil('\n');}
void draw() {
background(255);
if (temps.size() < 2) return; // mindestens 2 Werte
// Max/Min Temperatur
float tMax = temps.get(0);
float tMin = temps.get(0);
for (float t : temps) {
if (t > tMax) tMax = t;
if (t < tMin) tMin = t; }
if (tMax == tMin) tMax = tMin + 1;
// Achsen
stroke(0);
line(margin, height-margin, width-margin, height-margin); // X-Achse
line(margin, margin, margin, height-margin); // Y-Achse
// Gridlines Y
int ySteps = 5;
for (int i = 0; i <= ySteps; i++) {
float yVal = map(i, 0, ySteps, height-margin, margin);
float tempVal = map(i, 0, ySteps, tMin, tMax);
stroke(200);
line(margin, yVal, width-margin, yVal);
fill(0);
textAlign(RIGHT, CENTER);
text(nf(tempVal, 1, 1) + " °C", margin-10, yVal); }
// X-Achse: Zeit als Strings
int n = temps.size();
for (int i = 0; i < n; i++) {
float xVal = map(i, 0, n-1, margin, width-margin);
stroke(200);
line(xVal, height-margin, xVal, margin);
fill(0);
textAlign(CENTER, TOP);
text(times.get(i), xVal, height-margin+5); }
// Kurve
stroke(255, 0, 0);
noFill();
beginShape();
for (int i = 0; i < n; i++) {
float x = map(i, 0, n-1, margin, width-margin);
float y = map(temps.get(i), tMin, tMax, height-margin, margin);
vertex(x, y);}
endShape();
// Achsenbeschriftung
fill(0);
textAlign(CENTER);
text("Zeit", width/2, height-10);
pushMatrix();
translate(15, height/2);
rotate(-HALF_PI);
text("Temperatur (°C)", 0, 0);
popMatrix();}
void serialEvent(Serial myPort) {
String line = myPort.readStringUntil('\n');
if (line != null) {
line = line.trim();
if (line.length() > 0) {
String[] parts = split(line, ',');
if (parts.length == 2) {
try {
String timeStr = parts[0];
float temp = float(parts[1]);
if (!Float.isNaN(temp)) {
times.add(timeStr);
temps.add(temp); }
}
catch (Exception e) {
println("Ungültige Zeile: " + line);}
} } }
saveFrame("Graph_Processing_Waagrecht.png");
// Fenster wird als PNG_Datei gespeichert
}



Hier ist die Beschriftung senkrecht angebracht. Der Programm-Code für Processing ist fast identisch bis auf den Befehl rotate(-HALF_PI); // 90° nach links drehen, der den String um 90 Grad dreht. Der Quellcode des Processing- Sketch kann hier heruntergeladen werden.
Processing-Sketch: Graphische Darstellung der Daten einer CSV-Datei mit senkrechter Beschriftung

3. ESP32 - graphische Darstellung mit Python/Matplotlib
Graphische Ausgabe der Daten von einer SD-Card mit Hilfe von Python/Matplotlib über den direkten Zugriff auf die SD-Card
Ähnlich wie mit der Processing-IDE gibt es auch mit Python zwei Möglichkeiten des Zugriffs auf die SD-Card und der graphischen Darstellung der gespeicherten Daten. Die einfachere Möglichkeit ist der direkte Zugriff auf die (CSV-)Datei. Die zu bearbeitende Datei muss hier im selben Verzeichnis liegen, in dem auch der Python-Code abgespeichert wurde. Das bedeutet insbesondere, dass man bevor man den Code ausführt, diesen abspeichern muss, um den Ort des Abspeicherns zu wissen. In diesen Ordner kopiert man dann die entsprechende CSV-Datei.
Das soll als erstes durchgeführt werden.
Der Python-Code

import matplotlib.pyplot as plt
import pandas as pd
# CSV-Datei einlesen
df = pd.read_csv("daten.csv", parse_dates=["Datum"])
# Daten anzeigen (optional)
print(df)
# Plot erstellen
plt.figure(figsize=(10, 5))
plt.plot(df["Datum"], df["Temperatur"], marker="o", linestyle="-")
# Formatierung
plt.title("Temperaturverlauf")
plt.xlabel("Datum")
plt.ylabel("Temperatur (°C)")
plt.grid(True)
# wenn die Beschriftung zu lang für die waagrechte Anordnung ist.
# kann man den Text auch drehen - hier um 45 Grad
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig("CSV_Datei_direkter_Zugriff_25_01_2026.png")
plt.show()
Python-Code: Graphische Darstellung mit Python/Matplotlib direkter Zugriff

Graphische Ausgabe der Daten von einer SD-Card mit Hilfe von Python/Matplotlib mit dem Zugriff über die serielle Schnittstelle auf die Daten der SD-Card.
Als erstes wird der Arduino-Sketch hochgeladen, der die Daten der CSV-Datei über die serielle Schnittstelle zur Verfügung stellt. Zur Überprüfung der Daten kann man den seriellen Monitor aufrufen (Reset-Button am ESP32 drücken). Dann ruft man das Python-Programm auf, nicht ohne den seriellen Monitor wegen der Belegung des Ports zu schließen. Jetzt muss auch hier noch einmal der Reset-Button gedrückt werden, um Zugriff auf die Daten über die serielle Schnittstelle zu erhalten.

Arduibo-Sketch
#include <SPI.h >
#include <SD.h >
File file;
void setup() {
Serial.begin(115200);
while (!Serial);
if (!SD.begin(5)) { // CS-Pin ggf. anpassen
Serial.println("SD Fehler");
return; }
file = SD.open("/zahlen.csv");
if (!file) {
Serial.println("Datei nicht gefunden");
return;}
// CSV senden
while (file.available()) {
Serial.println(file.readStringUntil('\n'));
delay(5); // kleine Bremse für Python
}
file.close();
Serial.println("EOF"); // Marker für Python
}
void loop() {}

Der Python-Code

import serial
import matplotlib.pyplot as plt
ser = serial.Serial(
port='/dev/ttyUSB0', # ggf. /dev/ttyACM0
baudrate=115200,
timeout=1
)
x = []
y = []
print("Empfange Daten vom ESP32...")
while True:
line = ser.readline().decode('utf-8').strip()
if not line:
continue
if line == "EOF":
print("Fertig")
break
try:
idx, val = line.split(',')
x.append(int(idx))
y.append(float(val))
except ValueError:
pass
ser.close()
plt.figure(figsize=(8, 4))
plt.plot(x, y, marker='o')
plt.xlabel("Index")
plt.ylabel("Wert")
plt.title("ESP32 Messwerte (SD → Serial → Raspberry Pi)")
plt.grid(True)
plt.savefig("grafik_24_01_2026.png")
plt.show()

Python-Code: Graphische Darstellung mit Python/Matplotlib Zugriff über ser. Schnittstelle