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, u.a. auf https://forum.arduino.cc/t/too-many-arguments-to-function-hw-timer-t/1389998, hat hervorgebracht, 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 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
https://arduino.stackexchange.com/questions/96504/timers-interrupt-is-not-working-in-esp32s2-board
