Zum Inhalt springen
Timer mit Arduino - Alternative zum Delay

Timer mit Arduino – Alternative zu Delays

    Die Delay-Funktion in Arduino ist sehr nützlich. Sie hält das laufende Programm um eine angegebene Zeit an. Doch hier liegt ebenfalls das Problem. Oft will man, dass das Programm weiter läuft, um z. B. auf Eingaben oder Sensorwerte reagieren zu können. Hier helfen Timer-Funktionen weiter.

    Beispiel mit Delay-Funktionen

    int led = 13;
    
    void setup() {
      pinMode(led, OUTPUT);
    }
    
    void loop() {
      digitalWrite(led, HIGH);
      delay(1000);            
      digitalWrite(led, LOW);
      delay(1000);           
    }

    Hier hilft das Konzept der Timer-Funktion. Dabei wird zu einem bestimmten Zeitpunkt eine Art Stoppuhr gestartet. Ist eine bestimmte Zeit erreicht, wird ein Ereignis ausgeführt.

    Das Arduino-Board hat zwar keine eingebaute Uhr, zählt aber doch die Millisekunden seit dem letzten Start mit. Der Befehl, mit dem man die Millisekunden erhalten kann, heißt:


    Sieh dir jetzt meinen neuen Arduino-Videokurs an: Jetzt ansehen!


    millis()

    Er liefert eine ganze Zahl im Wertebereich long zurück (Der Variablentyp long ist wie int, jedoch mit größerem Wertebereich bis 2 147 483 647).

    Wir können millis() also als Referenzpunkt verwenden. D.h., wir speichern die aktuellen Millisekunden zu einem bestimmten Zeitpunkt in der Variable myTimer. Nun prüfen wir im weiteren Programmverlauf regelmäßig, ob dieser gespeicherte Zeitpunkt plus einer festgelegten Intervall-Zeit kleiner ist, als die aktuelle Zeit: Ist (Aktuelle Zeit > Startzeitpunkt + Intervall)?

    if (millis() > myTimeout + myTimer) { ... }

    Sobald diese Bedingung wahr ist, wird der Inhalt in den geschweiften Klammern ausgeführt. Im Beispiel wird also eine Variable ledState umgekehrt und ihr Wert per digitalWrite() an eine LED geschickt. Wichtig ist, dass wir die Variable myTimer auf die aktuelle Zeit setzen:

    myTimer = millis(); 

    Stell es dir so vor, als ob du eine Stoppuhr zurücksetzt. Insgesamt sieht das Programm dann so aus:

    const int ledPin =  10;
    
    int ledState = LOW;
    long myTimer = 0;
    long myTimeout = 1000;
    
    void setup() {
      pinMode(ledPin, OUTPUT);
    }
    
    void loop() {
      if (millis() > myTimeout + myTimer ) {
        myTimer = millis();
    
        if (ledState == LOW) ledState = HIGH;
        else ledState = LOW;
    
        digitalWrite(ledPin, ledState);
      }
    }

    Dieses Vorgehen hilft bei vielen Programmen, die man nicht mit einem Delay blockieren will. Sehen wir uns ein Programm an, das zwei LEDs in unterschiedlichen Geschwindigkeiten blinken lässt:

    const int ledPin1 =  10;
    const int ledPin2 =  8;
    
    int ledState1 = LOW;
    long myTimer1 = 0;
    long myTimeout1 = 700;
    
    int ledState2 = LOW;
    long myTimer2 = 0;
    long myTimeout2 = 200;
    
    
    void setup() {
      pinMode(ledPin1, OUTPUT);
      pinMode(ledPin2, OUTPUT);
    }
    
    void loop() {
      if (millis() > myTimeout1 + myTimer1 ) {
        myTimer1 = millis();
    
        if (ledState1 == LOW) ledState1 = HIGH;
        else ledState1 = LOW;
    
        digitalWrite(ledPin1, ledState1);
      }
    
      if (millis() > myTimeout2 + myTimer2 ) {
        myTimer2 = millis();
    
        if (ledState2 == LOW) ledState2 = HIGH;
        else ledState2 = LOW;
    
        digitalWrite(ledPin2, ledState2);
      }
    }

    Der Modulo Trick – Ein einfacher Timer mit Arduino

    Manchmal will man aber einfach nur eine regelmäßige Funktion ohne delay()-Befehle ausführen. Dafür gibt es einen eleganten Weg: der Modulo-Operator %. Dieser liefert den Rest einer Division. Teilt man z.B. millis() durch 1000 wird eine Zahl von 0 bis 999 zurückgeliefert. Damit lässt sich doch was anfangen. Wenn du jetzt diese Zahl darauf prüfst, ob sie größer oder kleiner als z.B. 500 ist, hast du eine Blink-Funktion ohne das Variablen-Wirrwarr.

    int led = 13;
    
    void setup() {
      pinMode(led, OUTPUT);
    }
    
    void loop() {
      if (millis() % 1000 > 500) {
        digitalWrite(led, HIGH);
      } else {
        digitalWrite(led, LOW);
      }
    }

    Ein Hinweis von Gottfried: Die millis()-Funktion springt nach ca. 50 Tagen wieder zurück auf 0. Wer also längere Timer benötigt, sollte entweder ein RTC-Modul und damit eine echte Uhrzeit nutzen, oder das folgende Tutorial ansehen: https://www.norwegiancreations.com/2018/10/arduino-tutorial-avoiding-the-overflow-issue-when-using-millis-and-micros/

    Ich hoffe, du findest das genauso cool, wie ich. Viel Spaß damit :-)


    Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!

    • Die beliebtesten Arduino-Projekte von StartHardware
    • Inklusive Schaltplan, Beschreibung und Code
    • Arduino-Schnellstart-Kapitel
    • Kompakter Programmierkurs


    13 Gedanken zu „Timer mit Arduino – Alternative zu Delays“

    1. Pingback: Ampelanlage mit Arduino – Mit Fussgängern und Fahrspuren

    2. Pingback: Intervall-Ausführung leicht gemacht: Timer für Arduino - Technik Blog

    3. Pingback: Leuchtturm und Leuchttonnen mit Arduino – Arduino Tutorial

    4. Hallo und zunächst vielen Dank für den Beitrag ! Die Modulo-Funktion ist eine ‘für den AVR’ recht
      aufwändige Funktion. Eine Subtraktion wäre hier auch machbar, zumal man das Problem mit dem Timer-Überlauf automatisch umgeht. Hier geht es ja nicht um einen 50-Tage Zeitraum sondern um eine Periode von ca. 1000 ms. Habe das gerade mal ausprobiert – die automatische Überlaufbehandlung hängt mit dem uint32_t zusammen, bei Subtraktion sollte der Wert automatisch immer korrekt sein.
      Auf den Überlauf habe ich allerdings jetzt nicht gewartet…

      uint32_t start_time = 0;
      uint32_t diff_time = 0;
      const uint32_t time_period = 999;

      void setup() {
      start_time = millis();
      }

      void loop()
      {
      diff_time = millis() – start_time;

      if(diff_time > 500) {
      digitalWrite(led, HIGH);
      }
      else {
      digitalWrite(led, LOW);
      }

      if(diff_time > time_period) {
      start_time = millis();
      }
      }

    5. Hallo Herr Hermann

      so wie Sie das hier erklären, ist es gut verständlich;
      nur leider hat der Code einen versteckten bösen Bug:
      der Millis Überlauf wird nicht berücksichtigt
      https://www.norwegiancreations.com/2018/10/arduino-tutorial-avoiding-the-overflow-issue-when-using-millis-and-micros/
      https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover
      dieser Beispiel-Code ist also nur für kleine Experimente brauchbar,
      aber nicht für ernsthafte Projekte
      das wär schön, wenn Sie da eine Warnung dazuschreiben würden ……..

      mit freundlichen Grüßen,
      Gottfried Silberhorn

      1. Hi Gottfried,

        ich hoffe, dass du ist ok. Danke für den Hinweis. Ich habe es in den Beitrag aufgenommen. Ich glaube, am besten würde man eine RTC verwenden, wenn man so lange Zeiträume ansehen will, aber die Lösung von Norwegiancreations ist auch cool.

        Liebe Grüße

        Stefan

    6. Guten Tag.
      Als Modelleisenbahner habe ich mich auch mit dem Arduino beschäftigt und besitze auch eine Grundausstattung. Durch ein neues Diorama Projekt einer Standseilbahn, bin ich auf der Suche nach einer Timerfunktion. Dabei bin ich auf diese Seite aufmerksam geworden.
      Ich betreibe die Seilbahn mit einem bistabilen Relays und H Schaltung und einem kleinen 6 Volt Motor. Mit jeweils einem Reed Kontakt wird der Motor gestoppt und umgepolt. Problem, jeweils am Endpunkt sollte ein zusätzlicher Kontakt eine Einschaltverzögerung ( keine Spannung ) von ca. 15 sec. auslösen. Danach soll der DC Motor wieder mit Strom versorgt werden usw. Gibt es dafür einen scetch?
      Herzliche Grüße
      Hans Karthaus

    7. Hallo.
      Ich hätte eine Frage. Wie kann ich es mit Millis realisieren das ich 10 taster habe und diese zu unterschiedlichen Zeiten drücke sodass eine LED für jede der 10 Taster für 3 min. leuchtet?
      Danke.

    8. Hallo Stefan,

      vielen Dank für Deinen Beitrag, Du hast mir echt wirklich gut weitergeholfen! Die Erklärung sehr anschaulich, gerade mit den beiden unterschiedlichen Timern am Ende. Das kann ich in meinem Programm gut verwenden!

      Viele Grüße
      Leo

    Schreibe einen Kommentar

    Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

     

    Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.