Anfänger braucht Hilfe bei Programm zur LED Steuerung

Hallo zusammen,
da ich eher aus der Hardware Ecke komme (Elektrotechniker) tu ich mir mit Programmierung noch etwas schwer. Ich möchte in Anhängigkeit von drei Schaltern zwei LEDs steuern. Leider scheitere ich schon an dieser vermeintlich einfachen Aufgabe.
Im Anhang mal ein Flußdiagramm wie ich mir das ganze vorstelle. Die drei Schalter sollen in einer Endlosschleife abgefragt werden und die LEDs entsprechend geschaltet werden.

Und hier mein Code dazu der leider nicht so funktioniert wie ich mir das vorstelle. Vielleicht kann mir einer von den Profis hier ein bissel auf die Sprünge helfen! Vielen Dank im vorraus!

#include <jled.h>
const int SwitchA = 7;
const int SwitchB = 6;
const int SwitchC = 5;
auto ledA = JLed(9);
auto ledB = JLed(10);
int ledpinA=9;
int ledpinB=10;
int SWB_old = 1;
int SWB_state = 1;
int SWA_old = 1;
int SWA_state = 1;

void setup() {
  pinMode(SwitchA, INPUT_PULLUP);
  pinMode(SwitchB, INPUT_PULLUP);
  pinMode(SwitchC, INPUT_PULLUP);
  }
  
void loop()
{
  
  ledA.Update();
  ledB.Update();
   
if (digitalRead(SwitchC) == LOW)
{   
   if (digitalRead(SwitchA) == LOW)
   {
    SWA_state = 0;
    
    if (ledA.IsRunning() == false && SWA_state != SWA_old)  //start again only if the sequence is not currently running
    {
      ledA.Reset().FadeOn(1000).Repeat(1);
      
      SWA_old = SWA_state;
    }
   }
      
  if (digitalRead(SwitchB) == LOW)
   {
    SWB_state = 0;
    
    if (ledB.IsRunning() == false && SWB_state != SWB_old)  //start again only if the sequence is not currently running
    {
      ledB.Reset().FadeOn(1000).Repeat(1);
      SWB_old = SWB_state;
    }
   }
}
if (digitalRead(SwitchC) == HIGH)
{
   if (digitalRead(SwitchA) == LOW)
   {
    SWA_state = 0;
    if (ledA.IsRunning() == false)  //start again only if the sequence is not currently running
    {
      ledA.Reset().Breathe(5000).Forever();
      SWA_old = 1;
    SWA_state = 1;
      
    }
   }

    if (digitalRead(SwitchB) == LOW)
   {
    SWB_state = 0;
    if (ledB.IsRunning() == false)  //start again only if the sequence is not currently running
    {
      ledB.Reset().Breathe(5000).Forever();
      SWB_old = 1;
    SWB_state = 1;
     
    }
   }
}
else{ 
  if (digitalRead(SwitchA) == HIGH)
  {
    ledA.Stop();
    SWA_old = 1;
    SWA_state = 1;
  }
  if (digitalRead(SwitchB) == HIGH)
  {
    ledB.Stop();
    SWB_old = 1;
    SWB_state = 1;
  }
}
}

Wenn die vielen if / else zu unübersichtlich sind, hilft eventuell die Tatsache, dass mit 3 Schaltern max. 8 Zustände möglich sind.

Aber bei dir ist es doch eigentlich einfacher:

  • Schalter A schaltet LED A, Schalter B schaltet LED B
  • Schalter C wechselt (beide LED) zwischen EIN und “Breathing” (wenn sie nicht sowieso AUS sind)

Wenn deine Library nicht einfach eine LED in einen der 3 Zustände {EIN, AUS, BREATHING} versetzen kann, schreib dir dazu eine Hilfsfunktion.

Und wenn du es in Wirklichkeit komplizierter haben willst (ich vermute mal “Langsames Hochfahren” zwischen AUS und EIN), brauchst du evtl. tatsächlich eine Flankenerkennung mit XXX_old und XXX_state.

Da keiner deine JLed Bibliothek kennt, ist es leider reine Raterei, was an deinem Sketch nicht so funktionert wie du es vielleicht gerne hättest.

Hi,

na ja mal von der Library ganz abgesehen, ist es genau das was ich versuche zu erreichen:

Aber bei dir ist es doch eigentlich einfacher:
- Schalter A schaltet LED A, Schalter B schaltet LED B
- Schalter C wechselt (beide LED) zwischen EIN und "Breathing" (wenn sie nicht sowieso AUS sind)

Leider ist das für einen blutigen Anfänger wie mich gar nicht so einfach........

michael_x:
Da keiner deine JLed Bibliothek kennt, ist es leider reine Raterei, was an deinem Sketch nicht so funktionert wie du es vielleicht gerne hättest.

Geht über den Bibliotheksverwalter zu installieren.

Hallo,

ich kenne die Funktion der Lib nicht aber du kannst es Dir mit der Logik etwas einfacher machen. Füge drei bool Variabel ein und lese die Schalter nur einmal ein. Anschliessend kannst Du die Hilfsvariablen logisch verknüpfen.

Etwa so:

const byte SwitchA = 7;
const byte SwitchB = 6;
const byte SwitchC = 5;

bool statA, statB, statC; // Status

void setup() {
  // put your setup code here, to run once:
  pinMode(SwitchA, INPUT_PULLUP);
  pinMode(SwitchB, INPUT_PULLUP);
  pinMode(SwitchC, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:

  statA = !digitalRead(SwitchA);
  statB = !digitalRead(SwitchB);
  statC = !digitalRead(SwitchC);

  if (statA & !statC) { // A und nicht C
    // LED A ein
  }

  else if(statA & statC) { // A und C
      // LED A breathe
    }

  else if (!statA) {   // A nicht
    //LED  aus
  }


}

Hallo,

Nachtrag , iich hab mal eben in die Beispiele für die Lib reingesehen , ich hab da auf Anhieb keines gefunden bei dem die "Betriebsart" einer LED im Loop geändert wird. Ich vermute das geht nicht so ohne weiteres. Kannst Du denn mit einem Schalter die LED ein und aus schalten ?

Ansonsten lass doch die Lib weg. LED faden ist mit millis() doch auch kein Hexenwerk

Heinz

Danke für die Anregung. Hab den Code mal entsprechend umgebaut:

#include <jled.h>
const byte SwitchA = 7;
const byte SwitchB = 6;
const byte SwitchC = 5;
bool statA, statB, statC; // Status
auto ledA = JLed(9);
auto ledB = JLed(10);
int ledpinA=9;
int ledpinB=10;
int SWB_old = 1;
int SWB_state = 1;
int SWA_old = 1;
int SWA_state = 1;

void setup() {
  pinMode(SwitchA, INPUT_PULLUP);
  pinMode(SwitchB, INPUT_PULLUP);
  pinMode(SwitchC, INPUT_PULLUP);
  }
  
void loop()
{

  statA = !digitalRead(SwitchA);
  statB = !digitalRead(SwitchB);
  statC = !digitalRead(SwitchC);
  
  ledA.Update();
  ledB.Update();
   
if (statA & !statC)
   {
    SWA_state = 0;
    
    if (ledA.IsRunning() == false && SWA_state != SWA_old)  //start again only if the sequence is not currently running
    {
      ledA.Reset().FadeOn(1000).Repeat(1);
      
      SWA_old = SWA_state;
    }
   }


if (statA & statC)
   {
    SWA_state = 0;
    
    if (ledA.IsRunning() == false && SWA_state != SWA_old)  //start again only if the sequence is not currently running
    {
      ledA.Reset().Breathe(5000).Repeat(1);
      
      SWA_old = SWA_state;
    }
   }

else if (!statA)
{
  ledA.Stop();
    SWA_old = 1;
    SWA_state = 1;
}


if (statB & !statC)
   {
    SWB_state = 0;
    
    if (ledB.IsRunning() == false && SWB_state != SWB_old)  //start again only if the sequence is not currently running
    {
      ledB.Reset().FadeOn(1000).Repeat(1);
      
      SWB_old = SWB_state;
    }
   }


if (statB & statC)
   {
    SWB_state = 0;
    
    if (ledB.IsRunning() == false && SWB_state != SWB_old)  //start again only if the sequence is not currently running
    {
      ledB.Reset().Breathe(5000).Repeat(1);
      
      SWB_old = SWB_state;
    }
   }

else if (!statB)
{
  ledB.Stop();
    SWB_old = 1;
    SWB_state = 1;
}
}

Das ganze funktioniert auch schon “Fast” gut. Ich kann mit den Schaltern A und B die LEDs einschalten. Aber wenn ich dann den Schalter C umlege passiert nichts. Erst wenn ich dann “C” eingeschaltet lasse und A oder B einmal aus und wieder anschalte wechselt die Betriebsart zu “breathing”…!

Ich hätte das ganze aber gerne so das die Betriebsart sofort von “An” auf “breathing” wechselt…

Hallo,

wie gesagt ich kenn die LIb nicht , denke aber es liegt daran das Du ja nur was machst wenn wenn runing false ist

if (ledB.IsRunning() == false && SWB_state != SWB_old),

was passiert wenn Du die If abfrage mal komplett raus lässt ?

Heinz

Rentner:
Ansonsten lass doch die Lib weg. LED faden ist mit millis() doch auch kein Hexenwerk

Finde ich auch:

const int SwitchA = 7;
const int SwitchB = 6;
const int SwitchC = 5;
const uint8_t FadeTable[] = {0, 3, 13, 33, 68, 118, 179, 232, 255};
const uint8_t FadeSteps = sizeof(FadeTable);
enum {OFF, ON, BREATH};
enum {ledA, ledB};

void setup() {
  pinMode(SwitchA, INPUT_PULLUP);
  pinMode(SwitchB, INPUT_PULLUP);
  pinMode(SwitchC, INPUT_PULLUP);
}

void fade(byte led, byte typ) {
  const byte ledpin[] = {9, 10};
  static byte step[] = {0, 0};
  static bool mehr[] = {1, 1};
  static uint32_t vorhin[] = {0, 0}, intervall = 100;

  if (millis() - vorhin[led] >= intervall) {
    vorhin[led] = millis();
    switch (typ) {
      case OFF:
        if (step[led] > 0) step[led]--;
        break;
      case ON:
        if (step[led] < FadeSteps - 1) step[led]++;
        break;
      case BREATH:
        if (mehr[led]) {
          if (step[led] < FadeSteps - 1) step[led]++;
        } else {
          if (step[led] > 0) step[led]--;
        }
        if (step[led] == 0 || step[led] == FadeSteps - 1) {
          mehr[led] = !mehr[led];
        }
        break;
    }
    analogWrite(ledpin[led], FadeTable[step[led]]);
  }
}

void loop() {
  if (digitalRead(SwitchC)) {
    if (digitalRead(SwitchA)) {
      fade(ledA, BREATH);
    } else {
      fade(ledA, OFF);
    }

    if (digitalRead(SwitchB)) {
      fade(ledB, BREATH);
    } else {
      fade(ledB, OFF);
    }
  } else {
    if (digitalRead(SwitchA)) {
      fade(ledA, ON);
    } else {
      fade(ledA, OFF);
    }

    if (digitalRead(SwitchB)) {
      fade(ledB, ON);
    } else {
      fade(ledB, OFF);
    }
  }
}

Ergänzung: Bei den Eingängen habe ich HIGH als ON interpretiert. Das kann man natürlich auch anders haben wollen. Die Lösung in #9 ist dann möglicherweise “sauberer”.

Du hast doch einen PAP, warum hast Du das Grundgerüst nicht danach gebaut?

void loop()
  {
  statA = !digitalRead(SwitchA);
  statB = !digitalRead(SwitchB);
  statC = !digitalRead(SwitchC);
  if (statC)   // statC=JA
    {
    if (statA) // statA=JA (Und statC=JA)
      {
      }
    else       // statA=NEIN (Und statC=Ja)
      {
      }
    if (statB) // statB=JA (Und statC=JA)
      {
      }
    else       // statB=NEIN (Und statC=Ja)
      {
      }
    }          // ENDE Zweig statC=JA
  else         // statC=NEIN
    {
    if (statA) // statA=JA (Und statC=NEIN)
      {
      }
    else       // statA=NEIN (Und statC=NEIN)
      {
      }
    if (statB) // statB=JA (Und statC=NEIN)
      {
      }
    else       // statB=NEIN (Und statc=NEIN)
      {
      }
    }          // Ende Zweig statC=NEIN
  }

agmue hat Dir fürs fade alles mitgegeben.

Wenn ich den PAP richtig gelesen habe, muss statB immer erst nach statA abgearbeitet werden und statC darf erst dann neu gelesen werden, nachdem statB durch ist.
Wenn sich statA und statB auch nach dem Eintritt in statC ändern dürfen, passt IMHO der PAP nicht mehr. Dann vergsiss das da oben.

Wenn ich den PAP richtig gelesen habe

... und wenn so ein PAP tatsächlich beschreibt was man will.
Da Led/Taster A von B völlig unabhängig ist, sollte die Reihenfolge egal sein.

Hallo zusammen,

der Code funktioniert jetzt so wie gewünscht. Ich bin selbst darauf gekommen woran es lag. Ich musste meine beiden Hilsvariablen die ich benutze um zu erkennen ob sich der Status eines Schalters geändert hat, noch an anderer Stelle zurücksetzen.

Jetzt funktioniert es wie gewünscht. Mit Schalter A und B lassen sich die LEDs aktivieren und in Abhängigkeit von Schalter C wird der eine oder andere Effekt gestartet. Zwischen denen dann auch mit Schalter C hin und her geschaltet werden kann.

Hier noch der funktionierende Code:

#include <jled.h>
const byte SwitchA = 7;
const byte SwitchB = 6;
const byte SwitchC = 5;
bool statA, statB, statC; // Status
auto ledA = JLed(9);
auto ledB = JLed(10);
int ledpinA=9;
int ledpinB=10;
int SWB_old = 1;
int SWB_state = 1;
int SWA_old = 1;
int SWA_state = 1;

void setup() 
{
  pinMode(SwitchA, INPUT_PULLUP);
  pinMode(SwitchB, INPUT_PULLUP);
  pinMode(SwitchC, INPUT_PULLUP);
}
  
void loop()
{
  statA = !digitalRead(SwitchA);
  statB = !digitalRead(SwitchB);
  statC = !digitalRead(SwitchC);
  
  ledA.Update();
  ledB.Update();
   
  if (statA & !statC)
  {
    SWA_state = 0;
    
    if (ledA.IsRunning() == false && SWA_state != SWA_old)  //start again only if the sequence is not currently running
    {
      ledA.Reset().FadeOn(1000).Repeat(1);
      SWA_old = SWA_state;
    }
  }

  if (statA & statC)
  {
    SWA_state = 0;
    
    if (ledA.IsRunning() == false)  //start again only if the sequence is not currently running
    {
      ledA.Reset().Breathe(5000).Repeat(1);
      SWA_old = 1;
      SWA_state = 1;
    }
  }

  else if (!statA)
  {
    ledA.Stop();
    SWA_old = 1;
    SWA_state = 1;
  }

  if (statB & !statC)
  {
    SWB_state = 0;
    
    if (ledB.IsRunning() == false && SWB_state != SWB_old)  //start again only if the sequence is not currently running
    {
      ledB.Reset().FadeOn(1000).Repeat(1);
      SWB_old = SWB_state;
    }
  }

  if (statB & statC)
  {
    SWB_state = 0;
    
    if (ledB.IsRunning() == false)  //start again only if the sequence is not currently running
    {
      ledB.Reset().Breathe(5000).Repeat(1);
      SWB_old = 1;
      SWB_state = 1;
    }
  }

  else if (!statB)
  {
    ledB.Stop();
    SWB_old = 1;
    SWB_state = 1;
  }
}

Hier noch der funktionierende Code

Vorbildliche Rückmeldung :slight_smile:

  • Sternchen verdient

Danke…!

Dachte mir vielleicht kann ja jemand anderes damit was anfangen…