[Projekt] INTERVAL

Flackereffekt mit wenigen Zeilen:

#include <INTERVAL.h>

long dauer[2];
const byte LED = 13;


void setup()
{
  pinMode(LED, OUTPUT);
}

void loop()
{
  INTERVAL(dauer[digitalRead(LED)])
  {
    
    dauer[0] = random(500) % 43 * 5;
    dauer[1] = random(500) % 43 * 2;
    digitalWrite(LED, !digitalRead(LED));
  }
}

Flackereffekt mit wenigen Zeilen:

Fein!

Ist es dir recht, wenn ich das bei den Beispielen mit aufnehme?

PS:
Eine winzige Änderung ist nötig um ein Warning des Compilers zu vermeiden:

unsigned long dauer[2];

ElEspanol:
random(500) % 43 * 5

beeindruckt ! 8) Was ist der wesentliche Unterschied zu random(215) ?

  • deins ist "grobkörniger" ?
  • Werte ( 0 .. 27 ) * 5 sind ca. 9% häufiger als (28 .. 42) * 5 ?

Macht das einen wichtigen Unterschied beim Flackern, hab ich was übersehen ? :wink:

michael_x:
Macht das einen wichtigen Unterschied beim Flackern, hab ich was übersehen ? :wink:

Keine Ahnung, ich hab mal ein paar Tests gemacht und so hat es mir gefallen. Sieht irgendwie nach dem Geflacker der Netzwerkaktivitäten am Switch aus.

Klar kannst du das in die Beispiele mit aufnehmen, mach noch ein paar passende Komentare rein, damit auch Neulinge es auf Anhieb verstehen.

Wem es gefällt, der Karmalink ist links :wink:

mach noch ein paar passende Komentare rein, damit auch Neulinge es auf Anhieb verstehen.

Ein Optimist, du bist!

Und Danke, lokal habe ich es schon drin.

combie:
Ist es dir recht, wenn ich das bei den Beispielen mit aufnehme?

Ich bewerbe mich mit dieser vereinfachten Variante:

#include <INTERVAL.h>

unsigned long dauer;
const byte LED = 13;

void setup()
{
  pinMode(LED, OUTPUT);
}

void loop()
{
  INTERVAL(dauer)
  {
    dauer = random(500) % 43 * 5;
    digitalWrite(LED, !digitalRead(LED));
  }
}

Ich schließe mich dem Lob der anderen gerne an :slight_smile:

auch die einfache Variante ist genehm.

Vielleicht solltest du in die Beispiele noch das mit aufnehmen, wo man unterschiedliche Hell-/Dunkelfasen hat. Das bereitet Anfängern auch gerne Probleme, wenn die von delay auf nicht blockierend umsteigen

ElEspanol:
auch die einfache Variante ist genehm.

Freut mich :slight_smile:

ElEspanol:
Vielleicht solltest du in die Beispiele noch das mit aufnehmen, wo man unterschiedliche Hell-/Dunkelfasen hat. Das bereitet Anfängern auch gerne Probleme, wenn die von delay auf nicht blockierend umsteigen

Meinst Du sowas:

#include <INTERVAL.h>

const byte LED = 8;
const unsigned long dauer[] = {200, 50, 50, 50};
const byte anzahlDauer = sizeof(dauer) / sizeof(dauer[0]);
byte index;

void setup()
{
  pinMode(LED, OUTPUT);
}

void loop()
{
  INTERVAL(dauer[index])
  {
    digitalWrite(LED, !digitalRead(LED));
    index = ++index % anzahlDauer;
  }
}

Es ist übrigens nicht erforderlich, die Intervall-Dauer mit einem unsigned long Datentyp zu versehen.

Wenn man nicht eigentlich ein Beispiel für den % Operator machen will, flackert auch

#include <INTERVAL.h>

const byte LED = 13;

void setup() {  pinMode(LED, OUTPUT); }

byte dauer;
void loop() {
  INTERVAL(dauer)  {
     dauer = random(200);
     digitalWrite(LED, !digitalRead(LED));
  }
}

agmue:
Meinst Du sowas:

#include <INTERVAL.h>

const byte LED = 8;
const unsigned long dauer = {200, 50, 50, 50};
const byte anzahlDauer = sizeof(dauer) / sizeof(dauer[0]);
byte index;

void setup()
{
  pinMode(LED, OUTPUT);
}

void loop()
{
  INTERVAL(dauer[index])
  {
    digitalWrite(LED, !digitalRead(LED));
    index = ++index % anzahlDauer;
  }
}

das ist schon fast zuviel des guten und von Anfängern nicht gleich nachzuvollziehen.

einfach mit

if(dauer==200) dauer=1000 else dauer=200;

das es jeder gleich blickt

Ich mag das Dingen und es kommt jetzt in meine Programme rein da ich viel mit "blink" merken arbeite,

if (goodidea==true && usable==true){
Karma++;
}

Gruß
DerDani

if (goodidea==true && usable==true){
Karma++;
}

dafür drück ich den Button :slight_smile:

Ich hätte da noch einen Verbesserungsvorschlag:

Es wird ja der Code erstmalig nach Verstreichen der Periodendauer ausgeführt.

Bei langen Perioden, z.B. loggen, wäre es aber günstig, vor allem beim testen, dass der Code sofort ausgeführt wird und dann erst die Wartezeit kommt.

Damit könnte man auch hervorragend Alarmmeldungen händeln.

if(alarm) INTERVAL(300000UL,1){sendsms();}

würde dann im Alarmfall eine SMS senden und alle 5 Minuten wieder, bis alarm 0 wird

Evtl. durch einen optionalen 2. Parameter wie im Beispiel?

Was haltet ihr davon?

Jede Wette, dann kannst du dich vor Karma nicht mehr retten :wink:

Nachtrag:
Der (aus kompatibilitätsgründen optionale) 2. Parameter könnte die Verzögerung bis zur ERSTmaligen Ausführung sein, also z.B.

INTERVAL(3600000UL,30000UL)
{
datenloggen();
}

30 Sekunden nach Systemstart werden die Daten erstmalig geloggt, dann alle Stunde

Bei langen Perioden, z.B. loggen, wäre es aber günstig, vor allem beim testen, dass der Code sofort ausgeführt wird und dann erst die Wartezeit kommt.

Wenn sichs nur ums Debuggen dreht, kann man den Zusatzcode auch mit #ifdef DEBUG aktivieren.
Schöner wird der Code dadurch dann leider nicht......

unsigned long dauer = 0;
void setup() {  pinMode(LED, OUTPUT); }


void loop() {
  INTERVAL(dauer)  {
     dauer =500;
     digitalWrite(LED, !digitalRead(LED));
  }
}

Evtl. durch einen optionalen 2. Parameter wie im Beispiel?

Hmmm....

Gegenvorschlag:
Dann eher ein 2tes Macro, fast identisch zu INTERVAL(), welches nur eine zusätzliche statische "firstRun" Variable mitführt/verwaltet.

Edit:

Nachtrag:
Der (aus kompatibilitätsgründen optionale) 2. Parameter könnte die Verzögerung bis zur ERSTmaligen Ausführung sein, also z.B.

Machbar!?!?
"firstRun" ins Macro einführen.

@ElEspanol

Die “neue” INTERVAL.H

#ifndef __INTERVAL__h__
#define __INTERVAL__h__

#include <Arduino.h>

extern bool DoINTERVAL; // Merker für das Interval Macro

// Start of Interval Macro
#define INTERVAL(interval)                     \
{                                              \
  static unsigned long lastHit = 0;            \
  DoINTERVAL = millis() - lastHit >= interval; \
  if(DoINTERVAL) lastHit = millis();           \
}                                              \
if(DoINTERVAL)
// End of Interval Macro 



// Start of Interval Macro
#define INTERVAL_FIRST(interval,firstInterval)                     \
{                                              \
  static unsigned long lastHit = 0;            \
  static bool firstRun = true;                 \
  DoINTERVAL = millis() - lastHit >= (firstRun?firstInterval:interval); \
  firstRun = false;                            \
  if(DoINTERVAL) lastHit = millis();           \
}                                              \
if(DoINTERVAL)
// End of Interval Macro 


#endif

Aufruf, dann z.B. so: (in Beispiel IntervalTest.ino)

void loop()
{
  // alter Kram
  // ...............

  // neu
   INTERVAL_FIRST(1000UL,0UL)
   {
     //Tu was alle 1000ms
     Serial.println(millis());
   }
}


Naja…
Gehen tuts schon…
Aber schöner oder schneller ist es nicht geworden…

Schöner muss es ja nicht werden, aber damit erschlägst du viele Probleme, von denen viele gar nicht wissen, dass sie sie haben.

Werds später Zuhause gleich mal testen.

Ich kann dir noch eine Variante bieten!
Du sprachest ja von “optionalen Parametern”.

Optionale Parameter in Macros sind ein Fluch, eine Qual.
Und für mich eigentlich außerhalb des erwünschten.

Aber da machbar, hier mal eine Vorführung:

Die “schlimme” INTERVAL.h

#ifndef __INTERVAL__h__
#define __INTERVAL__h__

#include <Arduino.h>

extern bool DoINTERVAL; // Merker für das Interval Macro


// Start of Interval Macro

#define INTERVAL_1(interval)                   \
{                                              \
  static unsigned long lastHit = 0;            \
  DoINTERVAL = millis() - lastHit >= interval; \
  if(DoINTERVAL) lastHit = millis();           \
}                                              \
if(DoINTERVAL)
// End of Interval Macro 


// Start of Interval Macro
#define INTERVAL_2(interval,firstInterval)     \
{                                              \
  static unsigned long lastHit = 0;            \
  static bool firstRun = true;                 \
  DoINTERVAL = millis() - lastHit >= (firstRun?firstInterval:interval); \
  if(DoINTERVAL)                   \
  {                                \
     lastHit = millis();           \
     firstRun = false;             \
  }                                \
}                                  \
if(DoINTERVAL)
// End of Interval Macro 

#define INTERVAL_X(x,A,B,INNER_INTERVAL, ...)  INNER_INTERVAL 

#define INTERVAL(...)    INTERVAL_X(,##__VA_ARGS__,\
                         INTERVAL_2(__VA_ARGS__),\
                         INTERVAL_1(__VA_ARGS__),\
                         INTERVAL_0(__VA_ARGS__)\
                                         ) 


#endif

Damit sind dann auch solche Dinge möglich:

void loop() 
{
   INTERVAL(1000UL,0UL)// starte sofort
   {
     //Tu was alle 1000ms
     Serial.println(millis());
   }
   
   INTERVAL(1000UL,4000UL) // starte erst nach 4 Sekunden
   {
     //Tu was alle 1000ms
     Serial.println(millis());
   }


   INTERVAL(333UL)
   {
     //Tu was alle 333ms
     Serial.println(333UL);
   }
}

Die "schlimme" INTERVAL.h scheint wirklich das gewünschte zu machen. Somit ist Schluss mit negativen previous-Werten, damit die Funktion direkt am Anfang ausgeführt wird.

Ich blick bei der Macro-Geschichte noch gar nicht durch. Deswegen Hut ab!

Karma++

P.S.: Für was sind die anderen Argumente?
#define INTERVAL_X(x,A,B,INNER_INTERVAL, ...) INNER_INTERVAL

ElEspanol:
P.S.: Für was sind die anderen Argumente?
#define INTERVAL_X(x,A,B,INNER_INTERVAL, ...) INNER_INTERVAL

Ich sach ja, gruselig....
Die anderen Parameter sind willkürlich benannt.

Im Grunde ist INTERVAL_X ein Dispatcher von einem "Variadic macro" zu Macros mit fester Parameter Liste.

Ich blick bei der Macro-Geschichte noch gar nicht durch.

Ich auch noch nicht....
Fundiertes Halbwissen, ja, aber viel mehr auch nicht.

Und wie du selber merkst, hier ist mit dem schlimmen INTERVAL Gedöns, die Grenze des "offensichtlichen Verhaltens" überschritten.
Auch verhalten sich, an der Stelle, die verschiedensten Compiler unterschiedlich.
Höllen tun sich auf.