Millies anstatt delay

Hey,
kurze Frage ich habe schon ein bisschen gesucht aber keine antwort auf meine Frage gefunden.
Ich habe viele LEDs da ich viele Probleme hatte weil ich mit "delay " gearbeitet habe, wollte ich jetzt fragen ob ich für mehrere LEDs mehrere "unsigned long previousMillis" brauche.
Also wenn ich Beispiels weise eine Status LED = Grün habe und eine Status LED = ROT habe muss ich den "unsigned long previousMillis" für jede LED machen und dann einfach in z. B. "unsigned long statusledokMillies " umbenennen?

Wenn du mehrere brauchst, dann wirst du auch mehrere anlegen müssen.

Aber ob du das benötigst, ist deinem Ablaufdiagramm und Schaltplan nicht entnehmbar.

Hier mal mein Sketch. Ich bin noch ziemlich am Anfang von der Arduino Materie. Deshalb sieht der Code auch dementsprechen aus.. Soll kein richtiges Projekt sein sondern nur zur Übung erstmal...
Würde der Code mit den Millies in der Theorie funktionieren?

const int statusledok = 12; //Grüne status LED wenn battery eingelegt ist
const int statusledfail = 8; //Rote status LED wenn keine battery eingelegt ist
const int batterylowVoltageled = 9;
const int batterymidVoltageled = 10;
const int batteryfullVoltageled = 11;
const int sensorValue = A0;
//int batteryValue = 0;
const int LEDblau = 2; // Farbe blau an Pin 3
const int LEDrot = 4; // Farbe rot an Pin 5
const int LEDgruen = 3; // Farbe gruen an Pin 6
int brightness1a = 150; // Zahlenwert zwischen 0 und 255 – gibt die Leuchtstärke der einzelnen Farbe an
int brightness1b = 150; // Zahlenwert zwischen 0 und 255 – gibt die Leuchtstärke der einzelnen Farbe an
int brightness1c = 150; // Zahlenwert zwischen 0 und 255 – gibt die Leuchtstärke der einzelnen Farbe an
const int dunkel = 0; // Zahlenwert 0 bedeutet Spannung 0V – also LED aus.
const int motorPin1 = 5;
const int motorPin2 = 13;

int ledStatestatusfail = LOW;
int ledStatestatusok = LOW;
int ledStatebatterylowVoltageled = LOW;
int ledStatebatterymidVoltageled = LOW;
int ledStatebatteryfullVoltageled = LOW;

const long interval = 1000;
unsigned long previousMillisStatusfail = 0;
unsigned long previousMillisStatusok = 0;
unsigned long previousMillisStatuslow = 0;

unsigned long currentMillisfail = millis();
unsigned long currentMillisok = millis();
unsigned long currentMillislow = millis();

//1,4 - 1,6 V keine battery
void setup() {

  Serial.begin(9600);
  pinMode(statusledok, OUTPUT);
  pinMode(statusledfail, OUTPUT);
  pinMode(batterylowVoltageled, OUTPUT);
  pinMode(batterymidVoltageled, OUTPUT);
  pinMode(batteryfullVoltageled, OUTPUT);
  pinMode(sensorValue, INPUT);
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);

}
void loop() {


  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023.00) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.00) * 2 /*/ 10/(100+10)*/;
  // print out the value you read:
  Serial.println(voltage);
  /*  digitalWrite(motorPin1, HIGH);
    delay(1000);
    digitalWrite (motorPin1, LOW);
  */
  if (voltage >= 0.00 && voltage <= 0.30) {
    analogWrite(LEDrot, brightness1b); // rot einschalten
    digitalWrite(statusledok, LOW);
    digitalWrite(batterylowVoltageled, LOW);
    digitalWrite(batterymidVoltageled, LOW);
    digitalWrite(batteryfullVoltageled, LOW);
    blinkfailbattery();

  }

  if (voltage >= 0.40 && voltage <= 0.90) {
    analogWrite(LEDgruen, brightness1c); // gruen Einschalten
    analogWrite(LEDrot, dunkel);
    digitalWrite(statusledok, HIGH);
    digitalWrite(statusledfail, LOW);
    //digitalWrite(batterylowVoltageled, LOW);
    digitalWrite(batterymidVoltageled, LOW);
    digitalWrite(batteryfullVoltageled, LOW);
   // blinklowVolatage();
  }

  if (voltage >= 1.00 && voltage <= 1.80) {
    digitalWrite(statusledok, HIGH);
    digitalWrite(statusledfail, LOW);
    digitalWrite(batterylowVoltageled, HIGH);
    digitalWrite(batterymidVoltageled, LOW);
    digitalWrite(batteryfullVoltageled, LOW);
  }
  if (voltage >= 2.00 && voltage <= 2.8) {
    digitalWrite(statusledok, HIGH);
    digitalWrite(statusledfail, LOW);
    digitalWrite(batterylowVoltageled, LOW);
    digitalWrite(batterymidVoltageled, HIGH);
    digitalWrite(batteryfullVoltageled, LOW);
    analogWrite(LEDblau, brightness1c);
  }

  if (voltage >= 3.00 && voltage  <= 5.00) {
    digitalWrite(statusledok, HIGH);
    digitalWrite(statusledfail, LOW);
    digitalWrite(batterylowVoltageled, LOW);
    digitalWrite(batterymidVoltageled, LOW);
    digitalWrite(batteryfullVoltageled, HIGH);
    analogWrite(LEDblau, brightness1c);
  }

}



void blinklowVolatage() {
  digitalWrite(batterylowVoltageled, HIGH);
  delay(300);
  digitalWrite(batterylowVoltageled, LOW);
  delay(300);


}
void blinkfailbattery() {
  if (currentMillisfail - previousMillisStatusfail >= interval) {
    previousMillisStatusfail = currentMillisfail;

    // if the LED is off turn it on and vice-versa:
    if (ledStatestatusfail == LOW) {
      ledStatestatusfail = HIGH;
    } else {
      ledStatestatusfail = LOW;
    }
    digitalWrite(statusledfail, ledStatestatusfail);
  }
}
void startup() {
  //CODE!

}
void allLEDs() {
  digitalWrite(statusledok, HIGH);
  digitalWrite(statusledfail, HIGH);
  digitalWrite(batterylowVoltageled, HIGH);
  digitalWrite(batterymidVoltageled, HIGH);
  digitalWrite(batteryfullVoltageled, HIGH);
}






void motorStop() {
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  //delay(500);
}

Zwar nicht die Lösung des Problems, aber das scheint wieder mal so ein Fall wo es sich anbietet ein struct mit den Daten anzulegen. Es scheint 3 LEDs zu geben, die alle gleichartige Variablen verwenden. Dann wäre der Code wenigstens übersichtlicher

Das hier:

if (ledStatestatusfail == LOW) {
      ledStatestatusfail = HIGH;
    } else {
      ledStatestatusfail = LOW;
    }

geht besser so:

ledStatestatusfail = !ledStatestatusfail;

was Meinst du genau mit Struct?

Dominik1313:
was Meinst du genau mit Struct?

Funktioniert dein Google doch nicht? Wenn ich was nicht kenne und es mich neugierig macht, suche ich im Internet erst mal danach... Auch wenn Struct nicht wirklich was für Anfänger ist, findest du zumindest Infos im Netz, was es ist! :wink:

Hey,
Ich habe gestern ca 2 Stunden darüber gelesen aber inwiefern soll ich das bei meinen LEDs anwenden? Das war die Frage..

Das ist doch offensichtlich!

Das C++ Schlüsselwort "struct" kommt von Struktur, oder strukturieren.
Man möchte dir sagen, dass du dein Programm besser strukturieren sollst!

Dann klärt sich deine Eingangsfrage quasi von selber.
Der Code wird übersichtlicher, wartungsfreundlicher, leichter zu debuggen. Es schleichen sich KEINE copy+paste Fehler ein, weil es kaum Codeduplikate gibt.

Mantra:
Fasse zusammen, was zusammen gehört.

Dazu rate ich dir, dich in das Thema "endliche Automaten"einzuarbeiten.
(und dann gehören diese Automaten natürlich auch wieder in Strukturen/Klassen gestopft)

Dominik1313:
Hey,
Ich habe gestern ca 2 Stunden darüber gelesen aber inwiefern soll ich das bei meinen LEDs anwenden? Das war die Frage..

Dann stelle zukünftig deine Frage

was Meinst du genau mit Struct?

so, dass man die auch versteht.

Du hast 5(?) LEDs die sich scheinbar genau gleich verhalten. Da bin ich mir nicht 100% sicher, aber es sieht so aus.

Also legt man eine Struktur an die eine LED beschreibt. z.B:

struct LED
{
   const byte pin;
   unsigned long lastMillis = 0;
   unsigned int brightness = 150;

   LED(byte pin) : pin(pin)
   {
   }
};

Jede LED bekommt ihre Variablen und Konstanten. Seit C+11 kann man die auch nun direkt hier initialisieren. Vorher ging das nicht

Dann kommt doch noch ein Konstruktor, so dass man beim Anlegen des Objekts nur einen Pin übergeben muss. Wenn du mehr Werte einstellen musst geht das auch hier. Stichwort: Initialisierungsliste

Dann erstellt man die LED Objekte und übergibt den Pin:

LED green(4);
LED red(5);
LED blue(6);

Die anderen Werte werden mit dem = initialisiert

Alternativ wenn immer das gleiche mit allen LEDs gemacht wird kann man sie auch in ein Array packen. Dann kann mit einer for-Schleife darüber iterieren. Das ist hier nicht immer der Fall.
Es gibt auch einen Weg sie je nach Bedarf einzeln oder zusammen anzusprechen, aber das lassen wir erst mal. Wird dich nur verwirren

Dann kann man einfach sowas machen:

pinMode(green.pin, OUTPUT);

...

digitalWrite(red.pin, HIGH);

Jede Eigenschaft wie "pin" und "lastMillis" hat dann automatisch den LED Namen davor

Nur mal für den Einstieg. Das lässt sich natürlich noch viel weiter treiben mit OOP, aber das muss erst mal nicht sein. Es ging nur darum das unübersichtliche Geflecht von Variablen aufzuräumen.

Man kann dann auch richtige Klasse draus machen (in C++ sind Strukturen und Klassen fast identisch). Dann kann man Methoden in die Klassen schreiben. z.B. eine blink() Methode die man ständig in loop() aufruft und das Blinken intern erledigt.
Aber wie gesagt als absoluter Anfänger nicht sofort nötig

also Wenn ich das jetzt richtig verstanden habe(Text nur überflogen) muss ich für jede led ein eigene Struct erstellen?
Dann stellt sich mir wieder die Frage ob das viel übersichtlicher ist?
Wenn ich zuhause bin habe ich mehr Zeit und Probier deinen Vorschlag mal aus

muss ich für jede led ein eigene Struct erstellen?

Nein!
Du erstellst die Struktur nur einmal.
Und erzeugst eine Instanz dieser Struktur für jede LED dieses Typs.

Dann stellt sich mir wieder die Frage ob das viel übersichtlicher ist?

Mir nicht.
Die Antwort lautet eindeutig: JA!

Hallo,

um noch mal auf Deine Eingangsfrage einzugehen. Du willst ja letztlich irgendwas zeitabhängig schalten. Wenn es mehr als einen zeitlichen Vorgang gleichzeitig geben soll benötigst Du in der Regel auch mehr als eine Variable previousMillis. Wie Du die übrigens nennst ist völlig wurscht, sinnvoller Weise kann man auch einen Namen verwenden der was mit der Funktion zu tun hat z.B "altBlinkMillis"

Beispiel:

nehmen wir mal an du hast eine Schrittkette "endlicher Automat" die immer nach Ablauf einer Zeit den nächsten Schritt ausführt. Dabei soll die Zeit für jeden Schritt unterschiedlich lang sein können. Dann kommst Du mit einer variablen previousMillis aus.

nehmen wir mal an du willst zwei LED rot & grün gleichzeitig unterschiedlich schnell blinken lassen und gleichzeitig noch was andres machen, dann würdest Du zwei unterschiedliche previousMillis verwenden. Ob du das dann letztlich mit einem Array , einer Struct , oder einer Classe löst wären meiner Meinung nach drei weitere Übngen zu den entsprechende Themen um die Unterschiede besser zu verstehen.

man kann auch 2 LED mit einer Schrittkette unterschiedlich schnell gleichzeitig blinken lassen was eigendich nur zeigt es führen viele Wege nach Rom.

Heinz

Dominik1313:
also Wenn ich das jetzt richtig verstanden habe(Text nur überflogen) muss ich für jede led ein eigene Struct erstellen?

Eine Struktur um eine LED zu beschreiben. Und dann beliebig viele Objekte/Instanzen dieser Struktur

Das geht davon aus das sich alle deine LEDs intern gleich verhalten. Und nur andere Dinge bedeuten, bzw. signalisieren. Soweit ich sehen kann ist das der Fall. Könnte aber auch falsch sein.
Wenn eine LED nicht blinken muss schadet es auch nichts wenn sie eine Millis-Variable hat. Dann kann sie halt blinken und tut es nicht

Dann stellt sich mir wieder die Frage ob das viel übersichtlicher ist?

Übersichtlicheres als

LED green(4);
LED red(5);

kann ich mir nicht vorstellen.

Dominik1313:
Würde der Code mit den Millies in der Theorie funktionieren?

Nein, da alle currentMillisX nicht aktualisiert werden.

Dominik1313:
Soll kein richtiges Projekt sein sondern nur zur Übung erstmal...

Dann mal auf die Zeit konzentriert (alle getestet mit UNO):

const int statusledok = 12; //Grüne status LED wenn battery eingelegt ist
const int statusledfail = 8; //Rote status LED wenn keine battery eingelegt ist
const int batterylowVoltageled = 9;
const int batterymidVoltageled = 10;
const int batteryfullVoltageled = 11;

const long interval = 1000;
unsigned long currentMillis = 0;

void setup() {
  pinMode(statusledok, OUTPUT);
  pinMode(statusledfail, OUTPUT);
  pinMode(batterylowVoltageled, OUTPUT);
  pinMode(batterymidVoltageled, OUTPUT);
  pinMode(batteryfullVoltageled, OUTPUT);
}

void loop() {
  currentMillis = millis();
  blinklowVoltage();
  blinkmidVoltage();
  blinkfailbattery();
}

void blinklowVoltage() {
  static unsigned long previousMillis = 0;
  if (currentMillis - previousMillis >= interval / 3) {
    previousMillis = currentMillis;
    digitalWrite(batterylowVoltageled, !digitalRead(batterylowVoltageled));
  }
}
void blinkmidVoltage() {
  static unsigned long previousMillis = 0;
  if (currentMillis - previousMillis >= interval / 7) {
    previousMillis = currentMillis;
    digitalWrite(batterymidVoltageled, !digitalRead(batterymidVoltageled));
  }
}
void blinkfailbattery() {
  static unsigned long previousMillis = 0;
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    digitalWrite(statusledfail, !digitalRead(statusledfail));
  }
}

Durch "static" wird eine eigene, nur in der Funktion sichtbare Variable angelegt, während currentMillis global angelegt und aktualisiert wird.

Die drei gleichen Funktionen rufen nach einer Zusammenfassung, was leicht über Felder geht:

const byte leds[] = {
  12, // Grüne status LED wenn battery eingelegt ist
  8,  // Rote status LED wenn keine battery eingelegt ist
  9,  // batterylowVoltageled
  10, // batterymidVoltageled
  11  // batteryfullVoltageled
};
const byte anzahlleds = sizeof(leds) / sizeof(leds[0]);
const unsigned int interval = 1000;
unsigned long currentMillis = 0;

void setup() {
  for (byte led = 0; led < anzahlleds; led++) {
    pinMode(leds[led], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  blinkLed(1);
  blinkLed(2);
  blinkLed(3);
}

void blinkLed(byte led) {
  static unsigned long previousMillis[] = {0, 0, 0, 0, 0};
  const unsigned int intervall[] = {interval, interval, interval / 7, interval / 3, interval};
  if (currentMillis - previousMillis[led] >= intervall[led]) {
    previousMillis[led] = currentMillis;
    digitalWrite(leds[led], !digitalRead(leds[led]));
  }
}

Nun kann man die Daten statt in mehrere Felder auch in eine Struktur packen, damit alles, was zu einer Led gehört, mit ihren Daten zusammen steht:

const unsigned int interval = 1000;
struct Led {
  const byte pin;
  const unsigned int intervall;
  unsigned long previousMillis;
};
Led leds[] = {
  // pin, intervall, previousMillis
  {12, interval, 0},      // Grüne status LED wenn battery eingelegt ist
  {8, interval, 0},       // Rote status LED wenn keine battery eingelegt ist
  {9, interval / 7, 0},   // batterylowVoltageled
  {10, interval / 3, 0},  // batterymidVoltageled
  {11, interval, 0}       // batteryfullVoltageled
};
const byte anzahlleds = sizeof(leds) / sizeof(leds[0]);
unsigned long currentMillis = 0;

void setup() {
  for (byte led = 0; led < anzahlleds; led++) {
    pinMode(leds[led].pin, OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  blinkLed(1);
  blinkLed(2);
  blinkLed(3);
}

void blinkLed(byte led) {
  if (currentMillis - leds[led].previousMillis >= leds[led].intervall) {
    leds[led].previousMillis = currentMillis;
    digitalWrite(leds[led].pin, !digitalRead(leds[led].pin));
  }
}

Hat man schon eine Struktur, ist es nur noch ein kleiner Schritt zu einer Klasse mit Methoden, denn erst dann werden die Vorteile einer Struktur richtig sichtbar:

const unsigned int interval = 1000;
unsigned long currentMillis = 0;
class Led {
    const byte pin;
    const unsigned int intervall;
    unsigned long previousMillis;
  public:
    Led(const byte pin, const unsigned int intervall)
      : pin(pin), intervall(intervall), previousMillis(0) {}

    void init() {
      pinMode(pin, OUTPUT);
    }
    void blink() {
      if (currentMillis - previousMillis >= intervall) {
        previousMillis = currentMillis;
        digitalWrite(pin, !digitalRead(pin));
      }
    }
};
Led leds[] = {
  // pin, intervall
  {12, interval},      // Grüne status LED wenn battery eingelegt ist
  {8, interval},       // Rote status LED wenn keine battery eingelegt ist
  {9, interval / 7},   // batterylowVoltageled
  {10, interval / 3},  // batterymidVoltageled
  {11, interval}       // batteryfullVoltageled
};

void setup() {
  for (Led &l : leds) l.init();
}

void loop() {
  currentMillis = millis();
  for (Led &l : leds) l.blink();
}

Ich habe bewußt ein paar Optimierungsmöglichkeiten wie enum ausgelassen, da könnte man also noch was verbessern.

Auf diesem Weg habe ich gelernt, andere mögen es als umständlich ansehen, aber ich kann ja nur meinen Weg zeigen. Sollte irgendjemand durch diesen Beitrag ein Aha-Erlebnis haben, so würde ich mich freuen.

Strukturen könnten auch Konstruktoren haben. Es gibt keine Grund ein Array aus Strukturen so unangenehm zu initialisieren und es erst bei Klassen richtig zu machen