Basic Sketche mit dem Microcontroller ESP32

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.

esp32-basics-001-breadboard

Schaltung für die Bauelemente des Heartbeat-Sketches:

esp32-basics-001-schaltung

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

esp32-basics-012-breadboard

x

esp32-basics-012-schaltung

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 count um 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://github.com/espressif/arduino-esp32/blob/3.0.2/libraries/ESP32/examples/Timer/RepeatTimer/RepeatTimer.ino#L42

x

Schreibe einen Kommentar