mehrfachzeiten, blink without delay

Hi, hab mal wieder ein problemchen mit dem programmiern,
es geht um ein Positionslicht das per Taster ein und ausgeschalten wird,

Ich bekomm es aber einfach nicht hin 3fach Zeiten zu Progammiern, mit delay kein Problem, aber es sollen später noch weitere funktionen hinzukommen.

Aus den Beispielen komm ich leider auch ncht weiter,
vielleicht kann mir ja dabei jemmand bischen helfen.

int led = 13;

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

void loop() {
 for (int x = 0; x <= 1; x++) {
  digitalWrite(led, HIGH);
  delay(20);
  digitalWrite(led, LOW);
  delay(70);
 }
  delay(1500);
}

Hi

Wo siehst Du das Problem?
Start bei 0
Licht an bei 0
Licht aus bei 20
Licht an bei 90
Licht aus bei 110

Licht an bei 1680 ...

Du musst doch 'nur' die Wartezeit individuell einstellen nach dem Schema 20,70,20,1570.

if (millis()-lasttick>=wartezeit){
 ...schalte LED um
 ...lasttick=millis();
 ...wartezeit 1 vor
}

Dort vll. für die Wartezeiten ein Array und den Index dafür hochzählen, bis das Array zu Ende ist, dann wieder bei 0 anfangen.

MfG

ohje, ich versuch das mal zu verstehn :o

Hallo,

ich sehe bei dir keine Taster.
Beschreibe doch noch einmal in klaren Worten was es wie werden soll.
Denn bei einem ein- und ausschalten per Taster benötige ich keine Zeiten.

ja, also den taster hab ich vorerst mal weggelassen,
es soll ein Positionslicht werden, für einen Motorschirm, am Gasgriff hab ich so ein taster mit dem man das Blinken ein, und bei wiederholtem Drücken wieder ausschalten kann.

Hab mal ein Video verlinkt, wie es im Moment aussieht mit dem Code

Positionslicht

Hallo,

um dich nicht gleich zu überfordern, nimm die Bounce2 Lib und programmiere dir einen Taster der wie ein Schalter wirkt. Bsp. anschauen. Led ein- und ausschalten mit jeden Tastendruck.

Dann lernste mit millis umgehen und programmierst dir ein Blinklicht.
Theseus erklärt millis()
http://forum.arduino.cc/index.php?topic=400102.msg2752141#msg2752141

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung
http://forum.arduino.cc/index.php?topic=423688.0

Das baust du dann aus sodaas es 2x blinkt.
Damit wären beide Teilaufgaben fertig.
Alles kombieren und läuft.
Und wenn du das schön aufgeräumt machst, zum Bsp. mit struct, dann ist es sehr leicht das von 2 auf 1000 Einheiten zu erweitern.

Vielen Dank,
werde mal mein Glück versuchen, auch wenn ich voll die Niete in sachen coding bin :slight_smile:

ich hab das mal so gemacht, aber es verhält sich wie delay :confused:

int led = 13;

unsigned long zeit_jetzt;

int interval_ein = 50;
int interval_aus = 100;
int interval_pause = 1500;

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

void loop() {
  for (int x = 0; x <= 1; x++) {
    zeit_jetzt = millis();

    while ((millis() - zeit_jetzt) < interval_ein) {
      digitalWrite(led, HIGH);
    }
    zeit_jetzt = millis();
    while ((millis() - zeit_jetzt) < interval_aus) {
      digitalWrite(led, LOW);
    }
  }
  zeit_jetzt = millis();
  while ((millis() - zeit_jetzt) < interval_pause) {
    digitalWrite(led, LOW);
  }
}

es verhält sich wie delay :confused:

siehst du im Beispiel BlinkWithoutDelay eine while Schleife?

Der Trick ist, dass loop() keine Zeit dauert, sondern nur einen (jeden) Zeitpunkt beschreibt: Wenn jetzt soviel Zeit seit ... vergangen ist, [ und/oder dies und das los ist ] dann ..

ich habe da was fertiges, das ich so oder in ähnlicher Form schon öfters gepostet habe.

Hier ein Beispiel mit 3 Objekten - mit unterschiedlichen Blinkmustern.
Das was du suchst ist die RhythmLed

/* Blink a LED in a specific rhythm

  Turns on and off light emitting diodes (LED) connected to a digital pin,
  without using the delay() function. This means that other code can run at the
  same time without being interrupted by the LED code.

  noiasca
  2019-05-05

*/

class BlinkLed {
    byte state = 1;       // 1 blink, 0 off
    unsigned long previousMillis;
    uint16_t on = 180;
    uint16_t off = 320;   // 180/320 is according ECE
    const byte ledPin;

  public:
    BlinkLed(byte attachTo):
      ledPin(attachTo)
    {}

    void begin()
    {
      pinMode(ledPin, OUTPUT);
    }

    void set(uint16_t _on, uint16_t _off)  // modify on/off times during runtime
    {
      on = _on;
      off = _off;
    }

    void setState(byte _state)            // 1 Switch on blinking; 0 switch off blinking
    {
      state = _state;
    }

    void tick()
    {
      if (state)
      {
        uint32_t currentMillis = millis();
        if (digitalRead(ledPin) && currentMillis - previousMillis >= on) {
          // save the last time you blinked the LED
          previousMillis = currentMillis;
          digitalWrite(ledPin, LOW);
        }
        if (!digitalRead(ledPin) && currentMillis - previousMillis >= off) {
          // save the last time you blinked the LED
          previousMillis = currentMillis;
          digitalWrite(ledPin, HIGH);
        }
      }
    }
};

class RhythmLed {
    byte state = 1;
    unsigned long previousMillis;
    const byte ledPin;
    uint8_t lengthOfPattern;
    // the intervall pattern
    //                          ON    OFF  ON   OFF
    //                          1     2    3    4
    uint16_t intervall[5] = {0, 150,  60, 20, 270};                  // ECE 2
    //uint16_t intervall[3] = {0, 180, 320};                         // ECE 1
    //uint16_t intervall[7] = {0, 25, 25, 25, 25, 25, 375};          // HELLA 3
    //uint16_t intervall[9] = {0, 40, 40, 40, 40, 40, 40, 40, 220 }; // HELLA 4
    //uint16_t intervall[5] = {0, 150,  60, 20, 400};                // wie gewünscht vom TO

  public:
    RhythmLed(byte attachTo):
      ledPin(attachTo)
    {}

    void begin()
    {
      pinMode(ledPin, OUTPUT);
      lengthOfPattern = sizeof(intervall) / sizeof(intervall[0]);
    }

    void setState(byte _state)
    {
      state = _state;
    }

    void setIntervall(uint16_t _intervall1, uint16_t _intervall2, uint16_t _intervall3, uint16_t _intervall4)       // Modify the intervalls to your needs
    {
      intervall[1] = _intervall1;
      intervall[2] = _intervall2;
      intervall[3] = _intervall3;
      if (lengthOfPattern>3) intervall[4] = _intervall4;   // if someone declares a dual-intervall, this line would crash the sketch, therefore this if on the index length ;-)
    }

    void tick()
    {
      uint32_t currentMillis = millis();
      if (state > 0)                            // iterate through the states 1 to n, we don't use state 0 because state 0 is reserved to "switch off" the light
      {
        if (currentMillis - previousMillis > intervall[state])
        {
          if (state % 2 == 1)  // all uneven states are ON, at the end of an intervall we switch to the oposite pin state
          {
            digitalWrite(ledPin, LOW);
          }
          else
          {
            digitalWrite(ledPin, HIGH);
          }
          state++;
          if (state > lengthOfPattern - 1) state = 1;
          previousMillis = currentMillis;
        }
      }
    }
};

BlinkLed myBlinkLed(9);       // a simple blink led
RhythmLed topRKL(13);         // define an output PIN for your LED
RhythmLed outOffSyncRKL(10);  // eine Rundumkennleuchte die wegen eines "Massefehlers" am Originalfahrzeugs eine leicht verschobene Blinkfrequenz hat ;-)

void setup()
{
  myBlinkLed.begin();
  topRKL.begin();
  outOffSyncRKL.begin();
  outOffSyncRKL.setIntervall(250,  90, 30, 400);  // Modify the intervalls for this LED
}

void loop()
{
  myBlinkLed.tick();  // each object has to be called once in the loop
  topRKL.tick();
  outOffSyncRKL.tick();

  // put here other code which needs to run:

}

Medolino73:
ich hab das mal so gemacht, aber es verhält sich wie delay :confused:

Dir fehlt noch eine Schrittkette:

const byte led = 13;

const unsigned int interval_ein = 50;
const unsigned int interval_aus = 100;
const unsigned int interval_pause = 1500;
unsigned long zeit_jetzt, zeit_vorhin;
byte schritt = 1;

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);
}

void loop() {
  zeit_jetzt = millis();
  switch (schritt) {
    case 1:
      if ((zeit_jetzt - zeit_vorhin) >= interval_ein) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, LOW);
        schritt = 2;
      }
      break;
    case 2:
      if ((zeit_jetzt - zeit_vorhin) >= interval_aus) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, LOW);
        schritt = 3;
      }
      break;
    case 3:
      if ((zeit_jetzt - zeit_vorhin) >= interval_pause) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, HIGH);
        schritt = 1;
      }
      break;
  }
}

Der Sinn des Programms erschließt sich mir nicht, daher verzichte ich auf Optimierungen, aber es sollte tun, was das Programm in #0 auch tut.

Hi

Wenn man nun noch die Schritt-Nummern per enum definiert, kann man sogar lesen, was wo passieren soll.

MfG

Ich schnall das einfach nicht, glaub ich mach das einfach mit einem attiny der nur diese eine Aufgabe übernimmt, und belasse es beim delay.

Hallo,

meine Version sieht wie folgt aus. Erstmal für einen Taster und eine zugehörige Led.
Die Blinkzeiten kannste ändern wie du lustig bist, solange das Paarweise erfolgt. Also immer On, Off Zeiten.
Am restlichen Sketch musste nichts ändern.
Solange der Taster gedrückt ist, solange werden alle Blinkzeiten durchlaufen.
Wird der Taster nicht mehr gedrückt wird die Blinksequenz komplett beendet. Hört also nicht plötzlich mittendrin auf.

Möchtest du eine Schalterfunktion des Tastern, musste die update_Taster() Funktion ändern bzw. Bounce2 verwenden.

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.8
  Arduino Mega2560
  05.05.2019
*/

unsigned long zeiten[] = {500,500,250,500,120,500,60,500};    // On,Off >> Zeiten immer Paarweise erweitern/kürzen
const byte anz_zeiten = sizeof(zeiten) / sizeof(zeiten[0]);
const byte pin_Taster = 2;
const byte pin_Led = 28;

void setup(void) {
  Serial.begin(9600);
  pinMode(pin_Taster, INPUT_PULLUP);
  pinMode(pin_Led, OUTPUT);
  Serial.println(anz_zeiten);               // Debug
}

void loop(void) {

  bool state = update_Taster();
  
  blinker(state, anz_zeiten);

}


bool update_Taster()
{
  static unsigned long last_ms = 0;
  const byte DEBOUNCE = 30;                 // Taster Entprellzeit
  bool state = false;
  
  if (millis() - last_ms > DEBOUNCE) {
    last_ms = millis();
    if (!digitalRead(pin_Taster)) {
      state = true;
    }
  }
  return state;
}


void blinker (bool run, const byte maxCount)                         
{
  enum state {idle, on, onWait, off, offWait, check};
  static state zustand = idle;
  static unsigned long last_ms = 0;
  unsigned long ms = millis();
  static byte count = 0;
  
  switch (zustand)
  {
    case idle:  if (run) {
                  count = 0;
                  zustand = on; 
                  Serial.println("on");               // Debug
                }
                break;

    case on:    digitalWrite(pin_Led, HIGH);
                last_ms = ms;
                zustand = onWait;
                Serial.println("onWait");             // Debug
                break;

   case onWait:   if (ms - last_ms > zeiten[count]) {   // On-Zeit abwarten
                    zustand = off; 
                    Serial.println("off");            // Debug
                  }
                  break;             

    case off:   digitalWrite(pin_Led, LOW);
                last_ms = ms;
                count++;                                // zum nächsten Zeiteintrag wechseln
                zustand = offWait;
                Serial.println("offWait");            // Debug
                break;

    case offWait: if (ms - last_ms > zeiten[count]) {   // Off-Zeit abwarten
                    zustand = check; 
                    Serial.println("check");          // Debug
                  }
                  break;             
                
    case check: if (count == maxCount-1) {            // Sind alle Zeiten abgearbeitet?
                  count = 0;
                  zustand = idle; 
                  Serial.println("idle");             // Debug
                }
                else {
                  last_ms = ms;
                  count++;
                  zustand = on; 
                  Serial.println("ON");               // Debug
                }  
                break;
  }
  
}

Hallo,

zurück zu deinem Problem.
millis ist deine Armbanduhr, die Tageszeit, die Uhr die ständig läuft.
Jetzt frage dich was du mit dieser Zeitinformation jeden Tag unbewusst machst um Wartezeiten zu überbrücken oder ähnliches. Die Erklärung von Theseus passt dazu sehr gut.

12min Pizza im Backofen. Du merkst dir die Zeit vom reinschieben und wartest bis diese Zeit plus 12min erreicht sind. Damit die Rechnung auf dem µC funktioniert müssen die Wertbereichsüberläufe beachtet werden. Deshalb addieren wir nicht sondern subtrahieren und vergleichen auf größer bzw. größer gleich.

Also fortlaufende Uhrzeit abzüglich der gemerkten Zeit des Pizza reinschiebens (Startzeit) ergibt die Differenzzeit. Wenn der Differenzwert gewünschte 12min erreicht hat, ist die Zeit um und wir erledigen die nächsten anstehen Dinge. Nämlich Backofen ausschalten und Pizaa schmecken lassen. In der Zwischenzeit haben wir Kaffee gekocht und den Tisch gedeckt. Weil wir ohne delay gewartet haben.

Ist Uhrzeit - gemerkte Zeit > Backzeit erreicht ?

Das Prinzip musste verstehen. Ist eigentlich nicht schwer.

Medolino73:
Ich schnall das einfach nicht,

Wenn Du genauer spezifizieren würdest, was Du nicht schnallst, dann könnte man Dir möglicherweise helfen. Wobei mit meinem Programm die LED des UNOs neben mir schön blinkt.

agmue:
Wenn Du genauer spezifizieren würdest, was Du nicht schnallst, dann könnte man Dir möglicherweise helfen. Wobei mit meinem Programm die LED des UNOs neben mir schön blinkt.

spiel mal den code auf den UNO damit du siehst was ich vorhab, das ganze soll über einen Taster aktiviert werden, das Blinken soll auch immer im loop sozusagen laufen, bis man erneut auf den Taster drückt um es zu deaktivieren.

int led = 13;

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

void loop() {
 for (int x = 0; x <= 1; x++) {
  digitalWrite(led, HIGH);
  delay(20);
  digitalWrite(led, LOW);
  delay(70);
 }
  delay(2000);
}

Möglicherweise ist es doch besser ich nehm einfach einen Attiny und steuer es extern dann an, Verwende zur zeit den Teensy 3.2.

Hallo,

weißt du was mich traurig macht, dass du es mit Bounce nicht einmal versucht hast.
Wofür hast du einen super schnellen Teensy wenn du nicht programmieren lernen möchtest?
Soll sich der ATtiny oder gar dein Teensy mit seinen hohen MHz mit delay langweilen?

Das ist noch nicht 100% nach OOP, sollte aber deinem Wunsch entsprechen.
Vorbereitungen für mehr Taster/Leds sind vorhanden.

Passe die Blitzzeiten in Zeile 9 an und die Pins und Pausenzeit in Zeile 50.
Die seriellen Ausgaben kannste rausnehmen wenn alles klar ist, die verfälschen die kurzen Blitzzeiten.

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.8
  Arduino Mega2560
  05.05.2019
*/

// On,Off >> Zeiten immer Paarweise erweitern/kürzen und Arraygröße anpassen
unsigned long zeiten[3][2] = {
  {20,70},    // ON / OFF
  {20,70},      
  {20,70},    // beliebig erweiterbar
};  
     
const byte sum_zeiten = sizeof(zeiten) / sizeof(zeiten[0]);

enum state {idle, on, onWait, off, offWait, pause, check};
  
struct Daten
{
  const byte pin_T;
  const byte pin_L;
  const unsigned long pause;
  const byte maxIndex;
  byte index = 0;
  unsigned long last_ms;
  enum state zustand;
  bool schalter;
  

  // Konstruktor
  Daten (byte T, byte L, unsigned long P, byte maxI) :
    pin_T(T),
    pin_L(L),
    pause(P),
    maxIndex(maxI),
    index(0),
    last_ms(0),
    zustand(idle),
    schalter(LOW) 
  {}

  void begin()
  {
    pinMode(pin_T, INPUT_PULLUP);
    pinMode(pin_L, OUTPUT);
  }
};

Daten blinker (2, 28, 1000, sum_zeiten);    // Pin Taster, Pin Led, Pause zwischen den Zyklen

void setup(void) {
  Serial.begin(9600);
  blinker.begin();
}

void loop(void) {

  blinker.schalter = update_Schalter(blinker.pin_T);
  blink_Steuerung(blinker.schalter);

}

/*
bool update_Taster(byte pin)
{
  static unsigned long last_ms = 0;
  const byte DEBOUNCE = 30;                 // Taster Entprellzeit
  bool state = false;
  
  if (millis() - last_ms > DEBOUNCE) {
    last_ms = millis();
    if (!digitalRead(pin)) {
      state = true;
    }
  }
  return state;
}
*/

bool update_Schalter(byte pin)
{
  static unsigned long last_ms = 0;
  const byte DEBOUNCE = 30;                 // Taster Entprellzeit
  static bool schalter = LOW;
  static bool old_state = HIGH;
  
  if (millis() - last_ms > DEBOUNCE) {
    last_ms = millis();
    bool state = digitalRead(pin);

    if (state == LOW && old_state == HIGH) {
        schalter = !schalter;
        Serial.print("schalter: ");
        Serial.println(schalter);
    }
    old_state = state; 
  }
  return schalter;
}

void blink_Steuerung (bool run)                         
{
  unsigned long ms = millis();

  switch (blinker.zustand)
  {
    case idle:  if (run) {
                  blinker.index = 0;
                  blinker.zustand = on; 
                  Serial.println("on");               // Debug
                }
                break;

    case on:    digitalWrite(blinker.pin_L, HIGH);
                blinker.last_ms = ms;
                blinker.zustand = onWait;
                Serial.println("onWait");             // Debug
                break;

   case onWait:   if (ms - blinker.last_ms > zeiten[blinker.index][0]) {   // On-Zeit abwarten
                    blinker.zustand = off; 
                    Serial.println("off");            // Debug
                  }
                  break;             

    case off:   digitalWrite(blinker.pin_L, LOW);
                blinker.last_ms = ms;
                blinker.zustand = offWait;
                Serial.println("offWait");            // Debug
                break;

    case offWait: if (ms - blinker.last_ms > zeiten[blinker.index][1]) {   // Off-Zeit abwarten
                    blinker.last_ms = ms;
                    blinker.zustand = check; 
                    Serial.println("check");          // Debug
                  }
                  break;      

    case check: if (blinker.index >= blinker.maxIndex-1) {            // Sind alle Zeiten abgearbeitet?
                  blinker.zustand = pause; 
                  Serial.println("pause");             // Debug
                }
                else {
                  blinker.last_ms = ms;
                  blinker.index++;                                // zum nächsten Zeiteintrag wechseln
                  blinker.zustand = on; 
                  Serial.println("ON");               // Debug
                }  
                break;

     case pause:  if (ms - blinker.last_ms > blinker.pause) {                // Pause abwarten
                    blinker.index = 0;
                    blinker.zustand = idle; 
                    Serial.println("idle");          // Debug
                  }
                  break;            
  }
  
}

Medolino73:
spiel mal den code auf den UNO damit du siehst was ich vorhab, ...

Sieht aus wie ein Doppelblitzer (= Positionslicht, jetzt hab ich's) getestet mit UNO:

const byte led = 13;

const unsigned int interval_ein = 50;
const unsigned int interval_aus = 100;
const unsigned int interval_pause = 1500;
unsigned long zeit_jetzt, zeit_vorhin;
byte schritt = 1;

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);
}

void loop() {
  zeit_jetzt = millis();
  switch (schritt) {
    case 1:
      if ((zeit_jetzt - zeit_vorhin) >= interval_ein) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, LOW);
        schritt = 2;
      }
      break;
    case 2:
      if ((zeit_jetzt - zeit_vorhin) >= interval_aus) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, HIGH);
        schritt = 3;
      }
      break;
    case 3:
      if ((zeit_jetzt - zeit_vorhin) >= interval_ein) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, LOW);
        schritt = 4;
      }
      break;
    case 4:
      if ((zeit_jetzt - zeit_vorhin) >= interval_pause) {
        zeit_vorhin = zeit_jetzt;
        digitalWrite(led, HIGH);
        schritt = 1;
      }
      break;
  }
}

Es gäbe dann auch noch die kurze Variante, getestet mit UNO:

const byte led = 13;

const unsigned int intervall[] = {50, 100, 50, 1500};
const byte anzahl = sizeof(intervall) / sizeof(intervall[0]);
unsigned long zeit_jetzt, zeit_vorhin;
byte schritt;

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);
}

void loop() {
  zeit_jetzt = millis();
  if ((zeit_jetzt - zeit_vorhin) >= intervall[schritt]) {
    zeit_vorhin = zeit_jetzt;
    digitalWrite(led, !digitalRead(led));
    schritt = (schritt + 1) % anzahl;
  }
}

Super, genau das was ich gesucht hatte, funktioniert einwandtfrrei, jetzt versuch ich das ganze mal mit dem Taster.
Vielen Dank :slight_smile: :slight_smile: