Heartbeat-Sketch
Der erste Sketch ESP32-Sketch-Heartbeat generiert mit der Arduino-IDE einen Heartbeat für den Microcontroller und gehört zur Rubrik Schauen-wir-mal-ob-alles-funktioniert. Die Arduino-IDE <hier noch Link> ist auf einem Windows- oder Linux-Rechner installiert. Der Microcontroller ESP32 <hier noch Link> ist über ein USB-Kabel (USB Micro B am Controller) angeschlossen, der Rechner erkennt den Controller. Ein Sketch, so heißt ein Programm in der Arduino-IDE, ist mit der Dateiendung *.ino in einem gleichlautenden Verzeichnis auf dem Rechner abgespeichert. Nach dem Speichern kompiliert man den Sketch in maschinenlesbaren Code für den Controller und überträgt ihn auf den Controller. Abschließend rebootet der Controller. Die Ausführung des Programms kann auf dem seriellen Monitor der Arduino-IDE verfolgt werden, wenn entsprechende Ausgaben im Code vorgesehen sind. I.d.R. sind dies die Serial.println-Kommandos des Sketchs.
- Über den Port GPIO2 wird eine LED ein- und ausgeschaltet.
- Der Port hat beim High-Pegel eine Spannung von 3,3 Volt.
- Die LED ist über einen Widerstand von 100 Ω (für ca. 10 mA) oder 47 Ω (für ca. 20 mA) gegen Masse angeschlossen.
- Die LED soll 100 ms lang ein- und 900 ms lang ausgeschaltet sein.
Die Schaltung ist auf einem Breadboard aufgebaut. Der Microcontroller ESP32 selbst ist für das Breadboard relativ breit. Ich habe dieses in der Mitte getrennt, dadurch ist seitlich des Controllers auch für die nachfolgenden Projekte ausreichend Steckplatz für weitere Bauelemente vorhanden.

Schaltung für die Bauelemente des Heartbeat-Sketches:

Das Listing zeigt den Code für den Sketch esp32-basics-001-heartbeat.ino:
// esp32-basics-001-heartbeat.ino
// die led blinkt im sekundentakt (100 ms/900 ms)
void setup() {
Serial.begin (115200); // uebertragungsgeschwindigkeit zum esp32 in bit/s
pinMode(2, OUTPUT); // gpio2 wird als ausgang gesetzt
digitalWrite(2, LOW); // gpio2 wird auf null gesetzt, die led damit initial ausgeschaltet
Serial.println ("ESP32 konfiguriert"); // ausgabe auf dem seriellen monitor der arduino-ide
}
void loop() {
digitalWrite(2, HIGH); // gpio2 wird auf eins gesetzt, die led damit eingeschaltet
Serial.println ("LED an"); // ausgabe auf dem seriellen monitor der arduino-ide
delay(100); // warteschleife 100 ms, bevor der naechste befehl die led ausschalten wird
digitalWrite(2, LOW); // gpio2 wird auf null gesetzt, die led damit ausgeschaltet
Serial.println ("LED aus"); // ausgabe auf dem seriellen monitor der arduino-ide
delay(900); // warteschleife 900 ms, bevor der naechste befehl die led ausschalten wird
}
Taster-Sketch
Der Einstiegs-Sketch Heartbeat liefert den Sekundentakt mit einer LED, um einfach nur sehen zu können, dass das System noch lebt. Der Sketch Timer schafft dagegen über die Nutzung eines Interrupts den Spielraum für das eigentliche Nutzprogramm.
Machen wir also den Schritt in die Richtung Nutzprogramm weiter, der Sketch Taster koppelt den Input durch einen Taster mit dem Output einer LED. Dabei sind der Taster und die LED Synonyme, hier können auch andere Sensoren oder Aktoren angeschlossen werden.
Funktion des Taster-Sketchs
x

x

x
//esp32-basics-012-taster.ino
#define LED_HEARTBEAT 2
#define LED_STATUS 5
#define TASTER 13
bool content;
void IRAM_ATTR isrHandlerOn(){
digitalWrite(LED_STATUS, HIGH);
}
void setup() {
Serial.begin (115200);
pinMode( LED_HEARTBEAT, OUTPUT);
digitalWrite(LED_HEARTBEAT, LOW); // led definitiv ausschalten
pinMode( LED_STATUS, OUTPUT);
digitalWrite(LED_STATUS, LOW); // led definitiv ausschalten
pinMode(TASTER, INPUT);
// interrupt durch taster
attachInterrupt(digitalPinToInterrupt(TASTER), isrHandlerOn, FALLING); // S.298
}
void loop() {
digitalWrite(LED_HEARTBEAT, HIGH);
Serial.println ("LED an");
delay(500);
digitalWrite(LED_HEARTBEAT, LOW);
Serial.println ("LED aus");
delay(500);
digitalWrite(LED_STATUS, LOW); // ausschalten status-led
}
x
Timer-Sketch
Der Heartbeat-Sketch hat einen entscheidenen Nachteil: Das Funktionieren des Programms und das Ein- und Ausschalten der LED wird über eine massive Zeitschleife (delay(100) bzw. delay(900)) erkauft. Das heißt, dass in einer extrem kurzen Zeit die Aktivität ausgeführt wird und danach die restliche Rechenzeit verbrannt wird. Dies ist sicher für Demozwecke geeignet, aber nicht für einen praktischen Einsatz. Hier kommt eine Variante eines Interrupts – im ESP-Kontext Timer genannt – zum Einsatz, dessen Funktion darin besteht, zu einem definierten Zeitpunkt bzw. Zeitabstand die eine oder überlappend mehrere Aktivitäten auszuführen und dazwischen den Rechner pausieren zu lassen. Diese Pause kann bei nachfolgenden Sketchen für weitere Aktionen genutzt werden. Der Sketch esp32-basics-010-timer soll dieses Prinzip darstellen. Die verwendete Hardware ist mit dem Heartbeat-Sketch identisch.
Ich hatte diesen Sketch schon vor einiger Zeit mal angearbeitet und jetzt festgestellt, dass er nicht mehr funktioniert. Eine Recherche im Netz hat geliefert, dass die Timer-Funktion mit dem Arduino-IDE-Boardmanager 3.0.0 geändert wurde. Beim Kompilieren des Codes wird die Fehlermeldung Compilation error: too many arguments to function ‚hw_timer_t* timerBegin(uint32_t)‘ ausgegeben. Die Änderungen im Sketch sind zwar minimal, aber auch signifikant. Ich habe dies weiter unten in den Listings vermerkt.
Das nachfolgende Listing gilt für den derzeit (September 2025) aktuellen Boardmanager ab Version 3.0.0, das nachfolgende kurze Listing zeigt die Setup-Definition, die verwendet werden muss, wenn ein Boardmanager in der Version <3.0.0 verwendet wird. Es besteht hier keine Abwärtskompatibilität.
Funktion des Timer-Sketchs
- Es wird keine harte Portdefinition verwendet, stattdessen erfolgt die Zuweisung des GPIO-Ports über das Makro LED_PIN.
- Löst der Timer aus, wird der Zähler
countum eins erhöht, er hat damit nacheinander eine gerade oder ungerade Zahl (Funktion onTime). - Im Setup erfolgen zuerst Standarddefinitionen zu Übertragungsgeschwindigkeit und GPIO-Port, dieser wird als Ausgang genutzt.
- xxx
Das Listing zeigt den Code für den Sketch esp32-basics-010-timer.ino:
// esp32-basics-010-timer.ino
#define LED_PIN 2 // erstellt das makro led_pin, dem der wert 2 zugewiesen wird
// timer // festlegungen timer
volatile int count; // integer zaehler count, durch volatile wird der wert vor jedem zugriff aus hauptspeicher gelesen
int totalInterrupts; // integer wert, zaehlt die anzahl der interrupts
hw_timer_t * myTimer = NULL; // erzeugt variable my_timer vom typ hw_timer_t
void IRAM_ATTR onTime() { // definition der funktion ontime(), iram_attr ist eine spezielle anweisung des esp32,
// es wird schneller interner RAM (IRAM) anstelle von flashspeicher genutzt
count++; // timer zaehlt counter um eins hoch
}
void setup() {
Serial.begin(115200); // uebertragungsgeschwindigkeit zum esp32 in bit/s
pinMode(LED_PIN, OUTPUT); // gpio2 wird als ausgang gesetzt
digitalWrite(LED_PIN, LOW); // led definitiv ausschalten
// 80Mhz: 80000000 / 80 = 1000000 tics / second
uint64_t alarmLimit = 1500000; // genau 64 bit breite integerzahl alarmlimit
myTimer = timerBegin(1000000); // timer initialisieren
timerAttachInterrupt(myTimer, &onTime); // interrupt konfigurieren, ordnet eine isr (interrupt service routine) zu
timerAlarm(myTimer, alarmLimit, true, 0); // true - timer neu gestartet, 0 - unendliche wiederholungen
}
void loop() {
if (count > 0) {
count--; // zuruecksetzen counter
totalInterrupts++; // anzahl der interrupts um eins erhoeht
Serial.print("Total Interrupts: "); // ausgabe auf dem seriellen monitor der arduino-ide
Serial.println(totalInterrupts); // ausgabe auf dem seriellen monitor der arduino-ide
if ( totalInterrupts%2 == 0) { // % = modulo-operator
digitalWrite(LED_PIN, HIGH); // einschalten, wenn counter gerade ist
} else {
digitalWrite(LED_PIN, LOW); // ausschalten, wenn counter ungerade ist
}
}
}
Die Timer-Funktion bis < Boardmanager 3.0.0 ist nicht aufwärtskompatibel, hier dazu das Listing. Die Setup-Routine wird komplett gegen die im Listing für den Boardmanager ab 3.0.0 ersetzt:
void setup() {
Serial.begin(115200); // uebertragungsgeschwindigkeit zum esp32 in bit/s
pinMode(LED_PIN, OUTPUT); // gpio2 wird als ausgang gesetzt
digitalWrite(LED_PIN, LOW); // led definitiv ausschalten
// 80Mhz: 80000000 / 80 = 1000000 tics / second
myTimer = timerBegin(0, 80, true); // timer initialisieren
timerAttachInterrupt(myTimer, &onTime, true); // interrupt konfigurieren, ordnet eine isr (interrupt service routine) zu
timerAlarmWrite(myTimer, 1000000, true); // setzt einen alarm zu jeder sekunde
timerAlarmEnable(myTimer);
}
Weitere Links zum Thema:
https://wolles-elektronikkiste.de/interrupts-teil-3-timer-interrupts
https://forum.arduino.cc/t/esp32-timer-reloading/1364408
x