Elegante Art Subroutinen in bestimmten Zeitabständen aufzurufen

Hallo, Ich benutze den folgenden Code um aus dem Mainloop einmal pro Sekunde in eine Subroutine zu springen. Dies erscheint mir jedoch wenig elegant. Kennt jemand eine schönere Art dieses zu lösen?

unsigned long letzteSekunde=0

Void loop()
{
unsigned long dieseSekunde=millis()/1000;
  
  if (letzteSekunde != dieseSekunde)
  {
    FunktionAufrufen();
    letzteSekunde=dieseSekunde;
  }
  }

INTERVAL.zip

#include <INTERVAL.h>
void setup(){}


Void loop()
{
  
  INTERVAL(1000)
  {
    FunktionAufrufen();
  }
}

Vielen Dank! Genau das habe ich gesucht!

Dies erscheint mir jedoch wenig elegant. Kennt jemand eine schönere Art dieses zu lösen?

Mir gefällt deine Lösung auch, irgendwie :wink:
Mal was anderes als der übliche previousmillis Vergleich.

Wenn man verstecken will wie es funktioniert, ist natürlich

#include "INTERVAL.h"

schön und (wenn man sich’s ansieht) trickreich, insbesondere bei mehreren unabhängigen Intervallen.

Deine Version braucht weniger RAM, dafür mehr FLASH als die INTERVAL Version :wink:

Mit dem üblichen BlinkWithoutDelay   if (millis() - prevmillis > interval)
hätte man das Optimum (der kleine RAM und weniger FLASH als die INTERVAL Version)

OK, um zu demonstrieren was “eleganter Code” bedeutet, ist INTERVAL.h ein schönes Beispiel.
Nicht dass jemand meint, ich meckere nur

Ich finde Deine Methode nicht so unelegant. Grüße Uwe

Ich bin mir da nicht so sicher…
Raketentechnik, oder Medizintechnik, ist das nicht.

Würde schätzen, dass sie nach 49 Tagen einmal einen Schluckauf bekommt…
Da 32Bit, im Überlauf, eben nicht regelmäßig durch 1000 teilbar ist.

Auch wenn es meist funktioniert, ist da doch ein prinzipieller Fehler drin, und der tut mir beim betrachten weh.

combie: Raketentechnik, oder Medizintechnik, ist das nicht.

Aber ich denke für die Steuerung eines Atomkraftwerks sollte es reichen :) :)

Wenn ihr schon am Vergleichen seid, wie schneidet diese elegante Lösung aus ALib0 ab?

 every(interval)  FunktionAufrufen();

Du meinst

/* by DoDi under MIT License */
//do something at regular intervals. This is designed for use in loop(), not within a task

typedef unsigned long millis_t; //unless defined elsewhere
#define every(ms) for (static millis_t _t=0; millis()-_t>=ms; _t+=ms)

Bei mir 8 Byte mehr FLASH als INTERVAL.h. Und um die MIT License habe ich mich nicht gekümmert ;)

Der Unterschied ist, dass mit dem every Makro bei Bedarf die Funktion mehrfach ausgeführt wird, wenn sie zu lange nicht dran kam.

Wenn das Programm so verbaut ist, daß regelmäßig aufzurufende Abläufe nicht rechtzeitig drankommen, dann sollte der Programierer ersetzt werden :-]

Mir war wichtig, daß sich die Zeitpunkte für die Aufrufe bei every() im Laufe der Zeit nicht verschieben, wie das bei vielen anderen Implementierungen der Fall ist.

DrDiettrich: Mir war wichtig, daß sich die Zeitpunkte für die Aufrufe bei every() im Laufe der Zeit nicht verschieben, wie das bei vielen anderen Implementierungen der Fall ist.

Das ist "bei vielen anderen Implementierungen" auch nicht der Fall, wenn die Rahmenbedingungen deinen strengen Kriterien genügen und keine Verzögerungen > 1ms auftreten :P ;) Aber ja, du hast recht: Dass ein Zyklus ganz ausfällt oder eben nicht, kommt erheblich seltener vor als dass sich der Zyklus bei Verzögerungen etwas verlängert. Und da ist

_t+=ms;  // ALib0.h

deutlich anders als

_t = millis();  // INTERVAL.h

Im einen Fall hat der Zyklus in jedem Fall die vorgegebene Mindestdauer, im anderen Fall das Intervall als Durchschnittswert, und immer die theoretische Anzahl an Ereignissen / Zeit.

Aber wenn es um "Eleganz" geht, und Eleganz bedeutet, dass versteckt wird was genau passiert, tun sich die zwei Makros nicht allzu viel.