3 Modi Relaissteuerung mit einem Taster

Servus liebes Arduino-Forum,

ich möchte mit meinem aktuellen Projekt vorerst ein Relais ansteuern.
Hierzu benutze ich einen Arduino nano, und die OneButton-Library. Der Arduino steuert einen BC547 an, der dann das Relais schalten lässt.
Insgesamt soll der Sketch 3 Modi beinhalten, welche ich mit einem Taster wechseln kann.
Drei Leds sollen den aktuell ausgewählten Modus anzeigen.
(LED1= Modus 1, LED2= Modus 2, LED3 = Modus 3)

Modus 1: LED1 leuchet, Relais = 10 sek. HIGH, 2 sek. LOW und dann wieder von vorn. Soll sich also unendlich wiederholen.

Modus 2: LED 2 leuchtet, Relais = 20 sek. HIGH, 2 sek. LOW ...)

Modus 3: LED3 leuchtet, Relais = 30 sek. HIGH, 2 sek. LOW) ...)

Ich bin schon so weit gekommen, dass ich zwischen zwei Modi hin und herschalten kann, aber hier komme ich zu meinem ersten Problem.

Problem 1: Und zwar wird der jeweilige Modus bei Betätigung nur einmal ausgeführt, und ich muss nachtriggern.
Wie gesagt, ich möchte, dass bei Betätigung des Tasters der jeweilige ausgewählte Modus solange ausgeführt wird, bis ich den Modus per Tastendruck ändere.
Komme leider auf keine Lösung bei diesem Problem.

Problem 2: Der Modus soll zu jedem Zeitpunkt geändert werden können.
Mit Delays ist das ein Problem, dass weiß ich.
Habe diesbezüglich mich auch schon mit Millis() beschäftigt, aber bekomme das Programm einfach nicht zum laufen.
Mit Delays habe ichs schon hinbekommen.

Problem 3: Würde gerne eine Reset-Funktion hinzufügen.
D.h. das Programm bei Betätigung z.B. eines Tasters wieder in den Anfangszustand zu setzen.

Sitze jetzt schon ziemlich lange an dem Programm und verzweifle allmählich. :drooling_face:
Habe auch schon einiges im Internet nachgelesen, aber komm einfach nicht weiter.

Hier mein Sketchversuch mit zwei Modi:

#include <OneButton.h>

unsigned long previousMillisLED1 = 0;
unsigned long previousMillisLED2 = 0;
unsigned long previousMillisMessen = 0;

// Konstanten
const int LED1 = 3;
const int LED2 = 4;
const int Relais = 5;

// Variablen
int intervalLED1 = 10000;
int intervalLED2 = 20000;
int intervalMessen = 2000;

OneButton button(A1, false);

void setup()
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(Relais, OUTPUT);

  button.attachClick(oneclick);
  button.attachDoubleClick(doubleclick);
}

void loop()
{
button.tick();

delay(10);
}

// Modus 1
void oneclick()
{
  unsigned long currentMillis = millis();
  digitalWrite(LED1, HIGH);
  digitalWrite(LED2, LOW);

  if ((unsigned long)currentMillis - previousMillisLED1 <= intervalLED1)
  {
    digitalWrite(Relais, HIGH);
    previousMillisLED1 = currentMillis;
  }
  else((unsigned long)currentMillis - previousMillisLED1 <= intervalMessen);
  {
    digitalWrite(Relais, LOW);
    previousMillisMessen = currentMillis;
  }
}

// Modus 2
void doubleclick()
{
  unsigned long currentMillis = millis();
  digitalWrite(LED2, HIGH);
  digitalWrite(LED1, LOW);

  if ((unsigned long)currentMillis - previousMillisLED2 <= intervalLED2)
  {
    digitalWrite(Relais, HIGH);
    previousMillisLED2 = currentMillis;
  }
  else((unsigned long)currentMillis - previousMillisLED2 <= intervalMessen);
  {
    digitalWrite(Relais, LOW);
    previousMillisMessen = currentMillis;
  }
}

Bitte seid ein bisschen nachsichtig was es das Programmieren an geht.
Habe leider nur die Grundkenntnisse in der Berufsschule gelernt, und das was ich mir bis jetzt selbst angeeignet habe.
:sweat_smile:
Ich bedanke mich schon mal für Eure Hilfe. :grinning:

Mfg

Wayne

Aha ein Östereicher. ( was an sich ja nichts schlimmes ist :wink: :wink: :wink: )

zu 1) such mal "Arduino toggle" da wird die Flankenerkennung benutzt. Dann zählst Du bei jeder Flanke eine Variable hoch (0 bis 2) und blinkst je nach dieser Variable (endlicher Automat).
zu 2) benutze millis() such nach "arduino nachtwächtererklährung"
zu 3) wo ist das Problem?

Pfiati Uwe

Hi

Du musst 'nachtriggern', da Du die Funktionen je nach 'Klick' eben nur 1x aufrufst.

Was willst Du wirklich?
Jetzt hast Du 1-fach-Klick für Funktion 1 und Doppel-Klick für Funktion 2.
Deine Beschreibung liest sich anders.

Du möchtest bei JEDEM 1-fach-Klick eine Variable 'Modus' um 1 hoch zählen.
Du möchtest bei JEDEM Doppel-Klick die Variable auf NULL zurück setzen (entspräche einem Reset).

In der loop() prüfst Du Modus und entscheidest darüber, was gemacht werden soll.
Entweder mit festen Abläufen - 10 Sekunden HIGH bei Modus 1, 20 Sekunden HIGH bei Modus 2 ... äh, ich sehe hier eine Vereinfachung:
Modus * 10 = Sekunden HIGH-Zeit.
Nach der HIGH-Zeit folgen (zumindest bist jetzt) immer 2 Sekunden LOW-Zeit.

Das schreit außerdem förmlich nach einer State-Maschine (wobei der Nachtwächter genau in diese Richtung geht).

MALE Dir auf, Was in welcher Reihenfolge abgearbeitet werden soll und schreibe an die Zwischenpfeile, welche Bedingung für diesen Schritt erfüllt sein muß.
Schon 'siehst' Du Deine State-Maschine vor Dir und kannst Sie nach diesen Vorgaben programmieren.

MfG

Servus,

@uwe Knapp daneben, komme aus Niederbayern. :stuck_out_tongue:
Vielen Dank für Eure Antworten.
Haben mir schon weitergeholfen. :slight_smile:
Es tritt nun ein neues Problem auf und ich komme nicht dahinter.
Ich kann jetzt zwischen den Modi hin- und herschalten und der ausgewählte Modus wiederholt sich auch. Klappt alles perfekt, aber nur die HIGH-Zeit des Relais wird korrekt ausgeführt.
Also bei Modus 1 bleibt das Relais 10 sek HIGH, bei Modus 2 bleibt es 20 sek HIGH ...
Nur die LOW-Zeit stimmt nicht.
Statt 2 sek LOW springt es sofort wieder auf HIGH um und die HIGH-Zeit beginnt von vorne.
Habe mich an der Nachtwächtererklärung orientiert und eig. alles 1:1 in meinen Sketch übernommen.
Wo ist mein Denkfehler?

Hier mein überarbeiteter Sketch:

//Millis()
unsigned long Relais_Zeit;

// Variablen
int LED1 = 2;  // Modus 1
int LED2 = 3;  // Modus 2
int LED3 = 4;  // Modus3
int button = 5;  // Taster
int relais = 6;  // Relais
int state = 0;  // Momentaner Status
int alt = 0;  // Alter Status
int buttonstate = 0;  // Tasterstatus
int Relaisstatus = LOW;

void setup() {
  pinMode(LED1, OUTPUT);  // Ein- und Ausgänge definieren
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(button, INPUT);
  pinMode(relais, OUTPUT);

  digitalWrite(LED1, LOW);  // Initialisierungsstatus ist "aus"
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  digitalWrite(relais, LOW);

}

void loop() {
  buttonstate = digitalRead(button);  // Entprellroutine
  if (buttonstate == 1)
  {
    delay(50);
    buttonstate = digitalRead(button);  // Status des Tasters abfragen
    if (buttonstate == 0)
    {
      state = alt + 1;
    }
  }
  else
  {
    delay(100);
  }
  switch (state)
  {
    //---------------------MODUS 1------------------------
    
    case 1:
      if (Relaisstatus == LOW)
      {
        if (millis() - Relais_Zeit > 2000);
      {
        digitalWrite(LED1, HIGH);
          digitalWrite(LED2, LOW);
          digitalWrite(LED3, LOW);
          digitalWrite(relais, HIGH);
          Relais_Zeit = millis();
          Relaisstatus = HIGH;
        }
      }
      else
      {
        if (millis() - Relais_Zeit > 10000)
        {
          digitalWrite(LED1, HIGH);
          digitalWrite(LED2, LOW);
          digitalWrite(LED3, LOW);
          digitalWrite(relais, LOW);
          Relaisstatus = LOW;
        }
      }
      alt = state;
      break;

    //------------------------MODUS 2--------------------------
    
    case 2:
      if (Relaisstatus == LOW)
      {
        if (millis() - Relais_Zeit > 2000);
      {
        digitalWrite(LED1, LOW);
          digitalWrite(LED2, HIGH);
          digitalWrite(LED3, LOW);
          digitalWrite(relais, HIGH);
          Relais_Zeit = millis();
          Relaisstatus = HIGH;
        }
      }
      else
      {
        if (millis() - Relais_Zeit > 20000)
        {
          digitalWrite(LED1, LOW);
          digitalWrite(LED2, HIGH);
          digitalWrite(LED3, LOW);
          digitalWrite(relais, LOW);
          Relaisstatus = LOW;
        }
      }
      alt = state;
      break;

      //--------------------MODUS 3-----------------------------
      case 3:
       if (Relaisstatus == LOW)
      {
        if (millis() - Relais_Zeit > 2000);
      {
        digitalWrite(LED1, LOW);
          digitalWrite(LED2, LOW);
          digitalWrite(LED3, HIGH);
          digitalWrite(relais, HIGH);
          Relais_Zeit = millis();
          Relaisstatus = HIGH;
        }
      }
      else
      {
        if (millis() - Relais_Zeit > 30000)
        {
          digitalWrite(LED1, LOW);
          digitalWrite(LED2, LOW);
          digitalWrite(LED3, HIGH);
          digitalWrite(relais, LOW);
          Relaisstatus = LOW;
        }
      }
      alt = state;
      break;

      //------------------------ANFANGSZUSTAND------------------------
      
      default:                      // wenn state nicht 1, 2, 3 ist
      digitalWrite(LED1, LOW);      // dann alle LED's und Relais LOW
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      digitalWrite(relais, LOW);
      alt = 0;
      break;
  }
}

Bin für jede Hilfe dankbar. :grinning:

Hi

if (millis() - Relais_Zeit > 2000);

Das macht NICHT, was DU glaubst.
Die folgende geschweifte Klammer-Auf gehört NICHT mehr zum IF, da Du Dieses per ; bereits beendet hast.

Das Tolle bei C&P-Code: Diesen Fehler hast Du in ALLEN Modi.

Da Dein Sketch äußerst knapp kommentiert ist, müsste ich mir den ganzen Thread erneut 'rein ziehen' um herauszulesen, was Deine Relais auf LOW machen - bin ich, ehrlich gesagt, zu faul für.

Sollte die abgebrochene IF nicht Dein Problem sein, kannst Du gerne einen weiteren Anlauf probieren.

MfG

Hi,

habe auch gerade das Problem mit Tastern.....mehrer Relais...mehrere Taster....
ich habe bei mir im Programm unterschiedliche lichtmodi die abgespeichert werden. Bei einem Taster funktioniert es ganz gut, mehrere Probleme mit der Überlagerung.
Hier ein Auszug aus meinem Programm, das ganze Programm findest du bei meinem Anliegen (mehrere Relais mit mehreren Tastern schalten)

Vielleicht hilft es dir.

 //taster 10
//wenn taster nciht gedrückt, licht aus
if (lichtmodus1 == 0)
{
  digitalWrite(ledpin2, HIGH);
  digitalWrite(ledpin4, HIGH);  
}
if (lichtmodus1 == 1)  //led an
{
  digitalWrite(ledpin2, LOW);
  digitalWrite(ledpin4, LOW);
}

if (lichtmodus1 >= 2)
{
  //lichtmodus = 0;
  digitalWrite(ledpin2, HIGH);
  digitalWrite(ledpin4, HIGH);
  lichtmodus1 = 0;
}

Servus,

also habe die Semicolons entfernt ( weiß selber nicht genau wieso ich die da reingeschrieben habe :cold_sweat: ), aber es hat sich nichts verändert. Zur Funktion des Relais: es schaltet im Moment nur zwischen zwei LED's hin- und her. Dient zu Signalisierungszwecken.

Habe aber ein paar Dinge festgestellt:

  1. Verändere ich den delay im else - Teil, dann ändert sich auch die LOW-Zeit meines Relais, und es läuft im loop. Wiederholt sich also, und ich kann ganz normal per Tastendruck in den nächsten Modus springen.
void loop() {
  buttonstate = digitalRead(button);     // Aktuellen Status des Tasters abfragen und unter "buttonstate" abspeichern
  if (buttonstate == 1)                  // Wenn Taster gedrückt wurde...
  {
    delay(50);                           // ... dann 50 ms warten
    buttonstate = digitalRead(button);   // Status des Tasters abfragen
    if (buttonstate == 0)                // Wenn Taster losgelassen wurde...
    {
      state = alt + 1;                   // ... dann wird wird der alte Status um 1 hochgezählt und wird zum aktuellen Status
    }
  }
    else                     
    {
     delay(100);<----------------Dieser Teil ist gemeint
    }
  1. Entferne ich den else-Teil, dann wird der gewünschte Modus wieder nur einmal ausgeführt. Modusänderung ist aber weiterhin problemlos möglich.

Ich habe im Internet nachgeforscht bzgl. toggeln, da uwe dies vorgeschlagen hat.
Leider blicke ich da nicht wirklich durch, wie ich das in meinen Sketch mit den drei Modi einbauen kann.
Könnte mir evtl. jemand eine kleine Erklärung liefern ggf. auch mit einem Sketchbeispiel?
Tut mir leid, vll. stehe ich auch einfach auf dem Schlauch und es ist eig. ganz einfach, aber wie gesagt bin jetz schon einige Tage dran, den Code zum laufen zu bringen und beiss mir da echt die Zähne dran aus. :slightly_frowning_face:

Hänge hier auch nochmal meinen aktuellen Sketch mit an. Hab ein paar Kommentare hinzugefügt. Hoffe es ist nun ein bisschen verständlicher. :slight_smile:

//Millis()
unsigned long Relais_Zeit;


// Variablen
int LED1 = 2;            // Signalisiert Modus 1
int LED2 = 3;            // Signalisiert Modus 2
int LED3 = 4;            // Signalisiert Modus 3
int button = 5;          // Taster
int relais = 6;          // Relais
int state = 0;           // Momentaner Status
int alt = 0;             // Alter Status
int buttonstate = 0;     // Tasterstatus
int Relaisstatus = LOW;  // Relaisstatus ist LOW

void setup() {
  pinMode(LED1, OUTPUT);    // Ein- und Ausgänge definieren
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(button, INPUT);
  pinMode(relais, OUTPUT);

  digitalWrite(LED1, LOW);  // Initialisierungsstatus ist "aus"
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  digitalWrite(relais, LOW);

}

void loop() {
  buttonstate = digitalRead(button);     // Aktuellen Status des Tasters abfragen und unter "buttonstate" abspeichern
  if (buttonstate == 1)                  // Wenn Taster gedrückt wurde...
  {
    delay(50);                           // ... dann 50 ms warten
    buttonstate = digitalRead(button);   // Status des Tasters abfragen
    if (buttonstate == 0)                // Wenn Taster losgelassen wurde...
    {
      state = alt + 1;                   // ... dann wird wird der alte Status um 1 hochgezählt und wird zum aktuellen Status
    }
  }
    else
    {
     delay(100);
    }
  
  switch (state)
  {
    //---------------------MODUS 1------------------------

    case 1:                                  //----------------Ist bei allen Modi gleich, nur Zeiten ändern sich----------------
      digitalWrite(LED1, HIGH);              // Gewünschte LED wird eingeschaltet um Modus zu signalisieren
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);

      if (Relaisstatus == LOW)               // Wenn Relais im Ruhezustand ist (LOW)...
      {
        if (millis() - Relais_Zeit > 2000)   // ...dann warten bis 2 Sekunden vergangen sind...
        {
          digitalWrite(relais, HIGH);        // ...dann Relais schalten lassen(HIGH)
          Relais_Zeit = millis();            // Momentane Relaiszeit wird zu millis()
          Relaisstatus = HIGH;               // Momentaner Relaisstatus ist HIGH
        }
      }
      else                                   // sonst ...
      {
        if (millis() - Relais_Zeit > 10000)  // ...warten bis 10 Sekunden vergangen sind...
        {
          digitalWrite(relais, LOW);         // ...dann Relais in Ruhezustand zurücksetzen (LOW)
          Relaisstatus = LOW;                // Momenatner Relaisstatus ist LOW
        }
      }
      alt = state;                           // Der alte Status wird zum neuen Status
      break;

    //------------------------MODUS 2--------------------------

    case 2:
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, HIGH);
      digitalWrite(LED3, LOW);
      
      if (Relaisstatus == LOW)
      {
        if (millis() - Relais_Zeit > 2000)
        {
          digitalWrite(relais, HIGH);
          Relais_Zeit = millis();
          Relaisstatus = HIGH;
        }
      }
      else
      {
        if (millis() - Relais_Zeit > 20000)
        {
          digitalWrite(relais, LOW);
          Relaisstatus = LOW;
        }
      }
      alt = state;
      break;

    //--------------------MODUS 3-----------------------------
    case 3:
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, HIGH);
      
      if (Relaisstatus == LOW)
      {
        if (millis() - Relais_Zeit > 2000)
        {
          digitalWrite(relais, HIGH);
          Relais_Zeit = millis();
          Relaisstatus = HIGH;
        }
      }
      else
      {
        if (millis() - Relais_Zeit > 30000)
        {
          digitalWrite(relais, LOW);
          Relaisstatus = LOW;
        }
      }
      alt = state;
      break;

    //------------------------ANFANGSZUSTAND------------------------

    default:                        // wenn der aktuelle Status nicht 1, 2, 3 ist
      digitalWrite(LED1, LOW);      // dann alle LED's und Relais LOW schalten
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      digitalWrite(relais, LOW);
      alt = 0;                      // der alte Status wird zurückgesetzt und es beginnt von vorne
      break;
  }
}