LED Statusanzeige durch Blinken

Hallo,

Nachdem ich seit einiger Zeit als stiller Mitleser bei euch reingeschnuppert habe und dabei sehr viel gelernt habe, bin ich nun an einem Punkt wo ich eure Hilfe brauche.

Zuerst der Code:

const byte VAaus = 2;                         //Relais VA aus
const byte VAueberbrueckt = 3;                //Relais VA überbrückung Überwchungsschalter
const byte led4wd = 4;                        //LED Taster 4/2WD Low
const byte taster4wd = 6;                     //Taster 4/2WD Low
unsigned long aktMillis, altMillis, blinkMillis;
unsigned int tastverz = 3000;                 //Verzögerungszeit taster gedrückt bis VA abgeschalten
unsigned int blinkverz = 200;                 //für LED Blinken bei ein und Ausschalten
bool zustand2wd = false;                      //4wdzustand = true -> 2WD, 4wdzustand = false -> 4WD
bool change4wd;                               //Variable ändern 2/4WD
bool blinkvalue = LOW;

void setup() {
  pinMode(led4wd, OUTPUT);                 //Muss Masse schalten (Transistor)
  pinMode(taster4wd, INPUT);               //Pullup, Schaltet Masse
  pinMode(VAueberbrueckt, OUTPUT);         //Schaltet Relais zum Antrieb VA abschalten (trennen)
  pinMode(VAaus, OUTPUT);                  //Überbrückt Überwachung VA aus (Fahrzeug "sieht" VA ein obwohl diese aus ist)

  digitalWrite(led4wd, LOW );               // set initial state
  digitalWrite(VAaus, LOW);                 // set initial state
  digitalWrite(VAueberbrueckt, LOW);        // set initial state
}

void loop()
{
  aktMillis = millis();     //millis zurücksetzen
  //blinkMillis = millis();


  //Taster gedrückt, LED blinkt bis Relais ein
  if ((digitalRead(taster4wd) == LOW) && (zustand2wd == false))
    if ((aktMillis) - blinkMillis > blinkverz)
    {
      blinkMillis = millis();               // Blinkmillis zurücksetzen
      blinkvalue = !blinkvalue;             // LED zustand2wd wecheln.
      digitalWrite(led4wd, blinkvalue);     // Wert auf den LED Ausgang schreiben

      // Beim Blinken und loslassen vom Taster immer mit LED aus stoppen, damit kurzes antippen von Taster nicht den falschen Zustand LED EIN hinterlassen kann
      if ((digitalRead(taster4wd) == LOW) && (blinkvalue == true))  //Prüfen Taster nicht gedrückt, während status Blinken aktiv
      {
        delay(blinkverz);                                           //damit blinken nicht abgewürgt wird
        digitalWrite(led4wd, !blinkvalue);                          //LED ende Blinkintervall ausschalten
      }
    }

  //Taster gedrückt, LED blinkt bis Relais aus
  if ((digitalRead(taster4wd) == LOW) && (zustand2wd == true))
    if ((aktMillis) - blinkMillis > blinkverz)
    {
      blinkMillis = millis();               // Blinkmillis zurücksetzen
      blinkvalue = !blinkvalue;             // LED zustand2wd wecheln.
      digitalWrite(led4wd, blinkvalue);     // Wert auf den LED Ausgang schreiben

      // Beim Blinken und loslassen vom Taster immer mit LED aus stoppen, damit kurzes antippen von Taster nicht den falschen Zustand LED EIN hinterlassen kann
      if ((digitalRead(taster4wd) == LOW) && (blinkvalue == true))  //Prüfen Taster nicht gedrückt, während status Blinken aktiv
      {
        delay(blinkverz);                                           //damit blinken nicht abgewürgt wird
        digitalWrite(!led4wd, !blinkvalue);                          //LED ende Blinkintervall ausschalten
      }
    }

  //Taster schltet mit verzögerung rel 1, dann 2 ein
  if (digitalRead(taster4wd) == LOW)
  {
    if ((aktMillis - altMillis >= tastverz) && change4wd)
    {
      change4wd = false;                                  //4wdchange = false;
      zustand2wd = !zustand2wd;                           //ausschalten = !ausschalten;

      digitalWrite(VAaus, zustand2wd);
      delay(1000);
      digitalWrite(VAueberbrueckt, zustand2wd);
      digitalWrite(led4wd, !change4wd);
    }
  }
  else
  {
    ((change4wd = true) && (digitalRead(taster4wd) == HIGH));
    altMillis = aktMillis;
  }

}

Konkret geht es um folgendes:
Wird ein Taster für länger als 3 Sekunden gedrückt soll Relais 1 eingeschalten werden und nach einer kurzen Zeit Relais 2 Eingeschalten werden. Danach soll nichts weiter geschehen bis der Taster losgelassen und erneut gedrückt wird. Bei erneutem drücken vom Taster, länger als 3 Sekunden soll zuerst wieder Relais 1 ausgeschalten und nach einer Pause Relais 2 ausgeschalten werden. Soweit funktioniert es (auch wenn es vermutlich viel optimierungspotential in meinem Code geben wird, ist mein erstes richtiges Projekt, also bitte nicht schlagen :wink: )

Die LED soll nun während der 3 Sekunden bevor die Relais ein und ausschalten blinken (auch das funktioniert) und wenn beide Relais ein sind den Zustand durch eine dauerhaft Leuchtende LED und wenn beide Relais aus sind mit einer dunklen LED angezeigt werden. Das funktioniert nicht so zuverlässig. Es wird der Status beibehalten der beim Blinken gerade aktiv war wenn ich die Taste loslasse. Und wenn ich die Taste kurz drücke fängt sie (korrekterweise) an zu blinken und bleibt dann in dem Zustand wo ich sie loslasse, sprich die Relais können eingeschalten sein, die LED aber aus und umgekehrt was dann keinerlei Aussagekraft mehr über den Schaltzustand der Relais hat.

Habt ihr eine Idee wie ich das umsetzen könnte.

Vielen Dank

Pinkpanter:
Zuerst der Code: ...

Eigentlich wollte ich mir Deinen Sketch mal vorknöpfen und hatte schon begonnen, ein bisschen darin herumzuformatieren (max. 80 Z. Breite z. B.). Aber ich habe gerade zu viele eigene Baustellen, um mich eingehend mit Deinem Code zu befassen.

Nur kurz: Versuche, mit 80 Z. pro Zeile auszukommen. Ich drucke Code gerne aus, um ihn unter die Lupe zu nehmen, da sind 80 Z. perfekt (= genau 1 Zeile in Festbreitenschrift). Probiere außerdem, auch Deine Kommentare mit einem „möglichst harmlosen“ Zeichen-Vorrat zu schreiben (keine Umlaute z. B.)

Gruß

Gregor

Hallo Gregor,

Hier nochmal überarbeitet

const byte VAaus = 2;           //Relais VA aus
const byte VAueberbrueckt = 3;  //Relais VA ueberbrueckung Ueberwchungsschalter
const byte led4wd = 4;          //LED Taster 4/2WD
const byte taster4wd = 6;       //Taster 4/2WD
unsigned long aktMillis, altMillis, blinkMillis;
unsigned int tastverz = 3000;   //Verzoegerungszeit Taster
unsigned int blinkverz = 200;   //LED Blinken bei ein- und ausschalten
bool zustand2wd = false;        //true -> 2WD, false -> 4WD
bool change4wd;                 //Variable aendern 2/4WD
bool blinkvalue = LOW;

void setup() {
  pinMode(led4wd, OUTPUT);       //Muss Masse schalten (Transistor)
  pinMode(taster4wd, INPUT);     //Pullup, schaltet Masse
  pinMode(VAueberbrueckt, OUTPUT);  //Relais zum Antrieb VA trennen
  pinMode(VAaus, OUTPUT);        //Ueberbrueckt Ueberwachung VA aus

  digitalWrite(led4wd, LOW );    // set initial state
  digitalWrite(VAaus, LOW);      // set initial state
  digitalWrite(VAueberbrueckt, LOW);  // set initial state
}

void loop()
{
  aktMillis = millis();     //millis zurücksetzen
  //blinkMillis = millis();


  //Taster gedrückt, LED blinkt bis Relais ein
  if ((digitalRead(taster4wd) == LOW) && (zustand2wd == false))
    if ((aktMillis) - blinkMillis > blinkverz)
    {
      blinkMillis = millis();            // Blinkmillis zurücksetzen
      blinkvalue = !blinkvalue;          // LED zustand2wd wecheln
      digitalWrite(led4wd, blinkvalue);  // Wert auf den LED Ausgang schreiben

      /* Beim Blinken und loslassen vom Taster immer mit LED aus stoppen
		 damit kurzes antippen von Taster nicht den falschen Zustand LED
		 EIN hinterlassen kann */		 
      //Prüfen Taster nicht gedrückt, während status Blinken aktiv:
	  if ((digitalRead(taster4wd) == LOW) && (blinkvalue == true))  
      {
        delay(blinkverz);        //damit blinken nicht abgewürgt wird
        digitalWrite(led4wd, !blinkvalue);   //LED ende Blinkintervall aus
      }
    }

  //Taster gedrückt, LED blinkt bis Relais aus
  if ((digitalRead(taster4wd) == LOW) && (zustand2wd == true))
    if ((aktMillis) - blinkMillis > blinkverz)
    {
      blinkMillis = millis();             // Blinkmillis zurücksetzen
      blinkvalue = !blinkvalue;           // LED zustand2wd wecheln.
      digitalWrite(led4wd, blinkvalue);   // Wert auf den LED Ausgang schreiben

      /* Beim Blinken und loslassen vom Taster immer mit LED aus stoppen,
	  damit kurzes antippen von Taster nicht den falschen Zustand LED
	  EIN hinterlassen kann */
	  //Prüfen Taster nicht gedrückt, während status Blinken aktiv:
      if ((digitalRead(taster4wd) == LOW) && (blinkvalue == true))  
      {
        delay(blinkverz);                 //damit blinken nicht abgewürgt wird
        digitalWrite(!led4wd, !blinkvalue);  //LED ende Blinkintervall aus
      }
    }

  //Taster schltet mit verzögerung rel 1, dann 2 ein
  if (digitalRead(taster4wd) == LOW)
  {
    if ((aktMillis - altMillis >= tastverz) && change4wd)
    {
      change4wd = false;                               
      zustand2wd = !zustand2wd;                        

      digitalWrite(VAaus, zustand2wd);
      delay(1000);
      digitalWrite(VAueberbrueckt, zustand2wd);
      digitalWrite(led4wd, !change4wd);
    }
  }
  else
  {
    ((change4wd = true) && (digitalRead(taster4wd) == HIGH));
    altMillis = aktMillis;
  }

}

Vielen Dank

((change4wd = true) && (digitalRead(taster4wd) == HIGH));

Dieser Ausdruck sieht recht Sinn frei aus!

else
  {
    ((change4wd = true) && (digitalRead(taster4wd) == HIGH));
    altMillis = aktMillis;
  }

Fehlt da ein IF?
falls ja dann ist change4wd = true falsch. ich sage nur = oder ==

Grüße Uwe

Hi

Mir ist der Sketch zu kompliziert - musste den Code 3x durchgehen, bevor mir auffiel, wo dann doch die Relais geschaltet werden - und Da war dann noch ein delay()...

Also während der Warterei zwischen den beiden Relais blinkt Da Mal Nichts.

Mein Vorschlag geht, wie in 90% der Threads hier irgendwie allgemein üblich, zur State-Maschine.
Ein Beispiel 'Blink_without'delay' gibt's in der IDE, den Nachtwächer hier im Forum.

Selber würde ich die Tasterei und die Zustandsänderungen der Relais in einer State-Maschine erschlagen.
Die Blinkerei geht 'nebenher', wenn die Relais unterschiedliche Status haben - dafür würde digitalWrite(LEDpin,millis()%100<50); reichen.
Sind Beide AN, ist die LED AN, sind Beide AUS, ist die LED AUS.

if (relaisA!=relaisB){
   digitalWrite(LED,millis()%100<50);  //unterschiedlich, alle 50ms toggeln
}else{
  digitalWrite(LED,relaisA);                    //identisch, LED auf Relais-Zustand
}

MfG

Bei mir würde das in etwa so aussehen...
(hoffentlich habe ich das Problem verstanden)

#include <CombiePin.h>
#include <CombieTimer.h>
#include <CombieTools.h>

Combie::Pin::OutputPin<4> led4wd;
Combie::Pin::OutputPin<2> VAaus;
Combie::Pin::OutputPin<3> VAueberbrueckt;
Combie::Pin::TasterGND<6> taster4wd;

Combie::Timer::EntprellTimer    entpreller(3000);
Combie::Timer::PpmGenerator     blinkgenerator(100,100); // generiert Blinkfrequenz
Combie::Timer::RisingEdgeTimer  ton(500); // einschaltverzoegerung
Combie::Timer::FallingEdgeTimer toff(500);// ausschaltverzoegerung

Combie::Tools::Counter<byte> counter;
Combie::Tools::FlankenErkennung flankenerkennung;

void setup() 
{
  led4wd.init();                 //Muss Masse schalten (Transistor)
  taster4wd.initPullup();        //Pullup, Schaltet Masse
  VAueberbrueckt.init();         //Schaltet Relais zum Antrieb VA abschalten (trennen)
  VAaus.init();                  //Überbrückt Überwachung VA aus (Fahrzeug "sieht" VA ein obwohl diese aus ist)
}

void loop()
{
  counter = flankenerkennung = entpreller = taster4wd;
  VAaus = counter & 1;
  VAueberbrueckt = toff = ton = VAaus;
  led4wd = (blinkgenerator && taster4wd) || VAueberbrueckt; 
}

Wie man sieht, halte ich wenig von if Kaskaden in loop.
Bevorzuge die Datenfluss Sichtweise.

CombieLib.zip (53.5 KB)

Hallo zusammen,

Vielen Dank. Hatte noch nicht die Zeit die Tips vertieft anzuschauen und umzusetzen, werde ich aber noch machen.

postmaster-ino:
Mir ist der Sketch zu kompliziert

Mir inzwischen auch :o :wink: Darum brauche ich auch eure Hilfe.

postmaster-ino:

  • und Da war dann noch ein delay()...

Also während der Warterei zwischen den beiden Relais blinkt Da Mal Nichts.

Ist mir klar, könnte ich aber, zumindest vorerst vermutlich damit leben. War nur so auf die Schnelle damit die Funktion da ist, der Sketch aber nicht mit noch einer millis-Abfrage im Moment noch Unübersichtlicher würde. Aber auch ohne das delay hab ich es noch nicht richtig zum laufen gebracht.

combie:
Bei mir würde das in etwa so aussehen...
(hoffentlich habe ich das Problem verstanden)

Danke für die Libs. Muss ich mir mal genauer anschauen, auf den ersten Blick sind sie sehr interessant.

combie:

void loop()

{
 counter = flankenerkennung = entpreller = taster4wd;
 VAaus = counter & 1;
 VAueberbrueckt = toff = ton = VAaus;
 led4wd = (blinkgenerator && taster4wd) || VAueberbrueckt;
}



Wie man sieht, halte ich wenig von if Kaskaden in loop.
Bevorzuge die Datenfluss Sichtweise.

Die Schreibweise kenne ich noch gar nicht und im Moment ist mir auch noch nicht ganz klar was da genau wann passiert und vor allem nicht wie ich darauf genau Einfluss nehmen kann. Da fehlen mir die Basics wohl noch. Sieht aber sehr kompakt und übersichtlich aus...
Habe es mal auf den Nano geladen. Einschalten funktioniert einwandfrei, ausschalten auch, nur das Blinken kommt beim ausschalten erst wenn die beiden Relais ausgeschalten sind. siehe Edit.

Ziel wäre folgendes:
Ausschalten -> Taster drücken, Blinken anfangen, nach 3 Sekunden Relais 1, kurz darauf Relais 2 ausschalten, LED ausschalten (darf auch weiterblinken solange die Taste gedrückt wird), sollte aber erst wieder einschalten nachdem die Taste losgelassen und wieder gedrückt wird.

Was jetzt zum Testen auch angenehmer wäre: Wenn nach dem einschalten nicht 3 Sekunden gewartet werden müsste bis ein erneuter Tastendruck (zum ausschalten) akzeptiert wird, aber das ist ein Detail.

Ich werde da noch ein bisschen einlesen müssen und mich dann daran herantasten...melde mich dann wieder.

Vielen Dank

Edit:
Hab es doch nicht sein lassen können...Das blinken, leuchten, nicht leuchten hab ich damit hinbekommen:

 led4wd = (blinkgenerator && taster4wd) || (VAueberbrueckt && !taster4wd);

Die Schreibweise kenne ich noch gar nicht und im Moment ist mir auch noch nicht ganz klar was da genau wann

Ja, das hätte mich auch gewundert....

Muss auch gestehen, das dieser Weg/Sichtweise nicht zu den beliebtesten hier im Forum gehört.
Ich bin also ein wenig "Verrückt". Vom "Normal" abweichend.

Normal wäre, einen großen Zustandsautomaten zu bauen. Einen Endlichen Automaten.
Das führt unweigerlich dazu, dass dieser Automat recht komplex wird.
Und Komplexität erhöht die Entwicklungszeit und Fehlerträchtigkeit.

Für diese Lib, habe ich über Monate nach Automaten in der Arduinowelt gesucht, und sie in Stücke gehackt. Gnadenlos fragmentiert. Kleine eigenständige Automaten gebaut, welche jeweils winzige Teilaufgaben erledigen.

Die Schreibweise selber....
Ich setze hier auf den Zuweisungsoperator (=).
Von allen verfügbaren, scheint er mir den Datenfluss am besten abzubilden.
Der (<<) wäre fast eine alternative, wenn er nicht schon 2 Bedeutungen hätte, eben Schieben und das Streaming. Dessen Verwendung würde unauflösbare semantische Problem aufwerfen.

Bewusst habe ich alternative Schreibweisen erlaubt/vorgesehen, weil klar ist, dass sich bei manchen Mitlesern alle Nackenhäärchen aufrichten, wenn es an die Operatorenüberladungen geht.

Beispiel:
Meine original Zeile (Datenfluss Sichtweise)

count = flankenerkennung = entpreller = taster4wd;

Die Daten flitzen von rechts nach links durch die Zeile
Jede der Stufen ist im Grunde ein kleiner spezialisierter endlicher Automat.
Diese Automaten verwalten intern Zustände und haben eine klare Eingabe und Ausgabe Schnittstelle.

Die Funktor Sichtweise

count(flankenerkennung(entpreller(taster4wd())));

Hier wird die Überladung des () Operators genutzt. Die Instanzen der Library Klassen verhalten sich jetzt wie Funktionen.

Und zu guter Letzt gibt es noch die Prozedurale/OPP Sichtweise:

counter.doTrigger(flankenerkennung.doTrigger(entpreller.doTrigger(taster4wd.pressed())));

Also ohne jede genutzte Operatoren Überladung.

Alle 3 Varianten sind von der Funktion her gleichwertig.
Unterscheiden sich aber im Flash Verbrauch etwas.

Sind aber alle sparsamer, mit Flash, als dein original Programm.
Der RAM Verbrauch ist bei meinen drei Varianten gleich.
Deins braucht erheblich weniger. Das ist der Zerstückelung des/der Automaten geschuldet.
Es werden bei meiner Methode mehr Zustands Variablen und Speicher für Zeiten benötigt.

Mir inzwischen auch :o :wink: Darum brauche ich auch eure Hilfe.

Mantra:

Wenn etwas zu komplex wird um es zu überblicken, dann zerlege es in Teilaufgaben.

Ändere den Standpunkt, dann verschiebt sich die Perspektive und man sieht "andere Bilder".

Edit:
Hab es doch nicht sein lassen können...Das blinken, leuchten, nicht leuchten hab ich damit hinbekommen:

Fein!