Zwei Knöpfe und zwei LEDs mit Timer

Hallo Forumsmitglieder,
ich bin grade dabei zwei Beleuchtungsszenarien per Knopfdruck zu realisieren und habe eigentlich nach vielem probieren ein Ergebnis, nur verstehe ich es nicht ganz :roll_eyes:
Eigentlich wollte ich zwei LEDs auf Knopfdruck mit unterschiedlichen Zeiten laufen lassen nur habe ich es nicht so wirklich geschafft, d.h. es ging die zweite Led nicht mehr aus. Dafür war der deaktivierte const long Interval2 gedacht, den ich dann natürlich für die zweite LED auch entsprechend abgefragt hatte. Also erst einmal auf zwei unterschiedliche Zeiten verzichtet und in beiden Szenarien mit dem gleichen Intervall gearbeitet, funktioniert im Prinzip auch. ABER..... beide LEDs leuchten unterschiedlich lang, z.B. wenn ich paralell drücke. Ist für meine simple Beleuchtung kein Problem, würde nur gerne wissen wo den Haken in meinem Sketch ist.


```cpp
// Pins für die LEDs
const int LED1 = 0;     
const int LED2 = 1;   

// Pins für die Taster
const int TasterLED1 = 2;
const int TasterLED2 = 3;   
     
// speichert den Status der LEDs: 0 = aus, 1 = ein
int Status1 = digitalRead(TasterLED1);
int Status2 = digitalRead(TasterLED2); 

unsigned long previousMillis = 0;  // will store last time LED was updated

// constants won't change:
const long interval1 = 5000;  // interval at which to blink (milliseconds)
//const long interval2 = 8000;  // interval at which to blink (milliseconds)

void setup()  
{
  // LEDs werden als OUTPUT (Ausgang) definiert
  pinMode(LED1, OUTPUT);  
  pinMode(LED2, OUTPUT);  

  // die Taster werden als INPUT (Eingang) deklariert
  pinMode(TasterLED1, INPUT_PULLUP);  
  pinMode(TasterLED2, INPUT_PULLUP);  
}
void loop() 
{  
  // Taster für die 1. LED abfragen
  Status1 = digitalRead(TasterLED1); 
  if (Status1 == LOW) 
    {digitalWrite(LED1, HIGH);}
   {unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval1)
       {previousMillis = currentMillis;
         { digitalWrite(LED1, LOW);}}
                               
  // Taster für die 2. LED abfragen
  Status2 = digitalRead(TasterLED2); 
  if (Status2 == LOW) 
 {digitalWrite(LED2, HIGH);}
 {unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval1)
   {previousMillis = currentMillis;
      { digitalWrite(LED2, LOW);}
 }}}}  
                          


Danke und Gruß
Prenzi

Dein Problem sind vermutlich Pin D0 und D1 (Leds), wenn es ein Uno o.ä ist.
Die solltest besser nicht nutzen, da diese vom USB-Treiber verwendet werde.

Wenn Du Dein Programm in der IDE mittels <Strg> + t formatieren läßt, erkennst Du eine Asymmetrie:


Da hast Du Dich wohl in der Klammerung vertan, was wohl zu einer Asymmetrie der Logik führt :slightly_smiling_face:

Außerdem mußt Du die Zeitmessung mit dem Tastendruck starten, nicht beim Löschen der LED.

Sechzehn Bits für einen Taster ist bei einem µC mit acht Bit Verschwendung, besser bool statt int:

bool Status1 = digitalRead(TasterLED1);
bool Status2 = digitalRead(TasterLED2);
1 Like

Hui...
<STRG> t

1 Like

Wenn man Deinen Code aufräumt, dann compiliert er und wird auch das machen, was Du Dir denkst.


// Pins für die LEDs
const byte LED1 = 0;
const byte LED2 = 1;

// Pins für die Taster
const byte TasterLED1 = 2;
const byte TasterLED2 = 3;

unsigned long previousMillis1;  // will store last time LED was updated
unsigned long previousMillis2;  // will store last time LED was updated

// constants won't change:
const unsigned long interval1 = 5000;  // interval at which to blink (milliseconds)
const unsigned long interval2 = 10000;
//const long interval2 = 8000;  // interval at which to blink (milliseconds)

void setup()
{
  // LEDs werden als OUTPUT (Ausgang) definiert
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  // die Taster werden als INPUT (Eingang) deklariert
  pinMode(TasterLED1, INPUT_PULLUP);
  pinMode(TasterLED2, INPUT_PULLUP);
}

void loop()
{
  // Taster für die 1. LED abfragen
  if (digitalRead(TasterLED1) == LOW)
  {
    digitalWrite(LED1, HIGH);
    previousMillis1 = millis();
  }
  if (millis() - previousMillis1 >= interval1)
  {
    digitalWrite(LED1, LOW);
  }
  // Taster für die 2. LED abfragen
  if (digitalRead(TasterLED2) == LOW)
  {
    digitalWrite(LED2, HIGH);
    previousMillis2 = millis();
  }
  if (millis() - previousMillis2 >= interval2)
  {
    digitalWrite(LED2, LOW);
  }
}

Das sieht nur nicht schön aus und hat den Makel, dass Du einmal verfügbaren Code nicht wiederverwendest, sondern komplett neu schreibst.

Das kann man ändern, indem man z.B. mit arrays arbeitet.
Dann kürzt sich das Ganze ein und Du läufst nicht Gefahr eine Variable aus einem Prozess in einem anderen zu benutzen.
Sähe dann so aus:


const byte anzahl = 2;

// Pins für die LEDs
const byte LED[anzahl] = {0, 1};

// Pins für die Taster
const byte TasterLED[anzahl] = {2, 3};

unsigned long previousMillis[anzahl] = {0, 0}; // will store last time LED was updated

// constants won't change:
const unsigned long interval[anzahl] = {5000, 10000}; // interval at which to blink (milliseconds)


void setup()
{
  // LEDs werden als OUTPUT (Ausgang) definiert
  for (byte b = 0; b < anzahl; b++)
  {
    pinMode(LED[b], OUTPUT);
    pinMode(TasterLED[b], INPUT_PULLUP);
  }
}
void loop()
{
  for (byte b = 0; b < anzahl; b++)
  {
    // Taster für die LED abfragen
    if (digitalRead(TasterLED[b]) == LOW)
    {
      digitalWrite(LED[b], HIGH);
      previousMillis[b] = millis();
    }
    if (millis() - previousMillis[b] >= interval[b])
    {
      digitalWrite(LED[b], LOW);
    }
  }
}

Man kann das sogar noch weiter treiben und kürzen :wink:

Das mit den PIN 0/1 wurde Dir ja schon gesagt - solange Du die serielle Schnittstelle nicht weiter brauchst, - z.B. für den Seriellen Monitor - geht das so in Ordnung, wird aber irgendwann nicht mehr gehen. Daher geich von vornherein ändern :slight_smile:

1 Like

nach dem @my_xy_projekt schon die ganze Tipparbeit abgenommen hat, könnte man nach der Einführung von Arrays auch noch den nächsten Schritt machen und Daten die zusammengehören zu Strukturen zusammenfassen.

struct Group {                  // eine Gruppe von zusammengehörenden Daten:
  const uint8_t led;            // Pin für die LED
  const uint8_t taster;         // Pin für denTaster
  const uint32_t interval;      // interval at which to blink (milliseconds)
  uint32_t previousMillis = 0;  // will store last time LED was updated
};

Group group[] {                 // ein Array von Gruppen
  {0, 2, 5000},                 // led, taster, interval
  {1, 3, 10000}
};

void setup() {
  for (auto &g : group) {               // g wird bei jedem Durchlauf zu einer Referenz auf eine Feld der Gruppe
    pinMode(g.led, OUTPUT);             // LEDs werden als OUTPUT (Ausgang) definiert
    pinMode(g.taster, INPUT_PULLUP);
  }
}

void loop() {
  for (auto &g : group) {
    if (digitalRead(g.taster) == LOW) {                   // Taster für die LED abfragen
      digitalWrite(g.led, HIGH);
      g.previousMillis = millis();
    }
    if (millis() - g.previousMillis >= g.interval) {  // prüfen ob Zeit abgelaufen ist
      digitalWrite(g.led, LOW);
    }
  }
}
2 Likes

Ich wusste doch, dass Du drauf anspringst :slight_smile: :+1:
Machste noch ne class draus?

du kennst mich schon viel zu gut.
Jetzt warten wir mal, dass @prenzi das geschriebene umsetzt, dann kann man OOP nachschießen.

1 Like

Ich mache mal die Klasse draus.

class Leds {
public:
  Leds(const byte ledPin, const byte tasterPin, unsigned long interval) :  ledPin{ledPin}, tasterPin{tasterPin}, interval{interval} {} 
  void init() {
    digitalWrite(ledPin, 0);
    pinMode(ledPin,OUTPUT);
    pinMode(tasterPin,INPUT_PULLUP); // Taster gegen GND
  }
  void run() {
    if (!digitalRead(tasterPin) && !status) {
      previousMillis = millis();
      status = true;
      digitalWrite(ledPin,status);
      return;
    }
    if (status && millis() - previousMillis >= interval) {
      status = false;
      digitalWrite(ledPin,status);
    }
  }
  
  unsigned long getInterval() {
    return interval;
  }
  
  void setInterval(unsigned long eInterval) {
    interval = eInterval;
  } 
  
private:
  const byte ledPin;
  const byte tasterPin;
  unsigned long interval;  // nicht const, damit man es ändern kann
  unsigned long previousMillis = 0;
  bool status = false;
};

// LEDs anlegen. Die Anzahl der Zeilen bestimmt die Anzahl der LEDs
Leds ledArr[] { //ledPin, TasterPin, Interval (ms)
                {2, 4, 1000},
                {3, 5, 500}
              };
constexpr byte ledAnz = sizeof(ledArr) / sizeof(ledArr[0]);

void setup() {
  for(byte i=0; i<ledAnz;i++) ledArr[i].init();
}             

void loop() {
  for(byte i=0; i<ledAnz;i++) ledArr[i].run();
}                

Ungetestet, aber kompiliert.

Gruß Tommy

1 Like

Erst einmal vielen Dank für die unkomplizierte und schnelle Hilfe, hatte mir hier schon wieder die Haare gerauft, dabei dachte ich, ich bin pfiffig und verwende das Bsp. 'blink without delay'und passe es an meine Anforderung an. Aber offensichtlich die Logik dann doch nicht richtig verstanden :worried:
Naja, Versuch mach Klug......
Wusste z.B. nicht das ich einfach previousMillis nummerieren kann und dieIntervalle als unsigned long definieren muss um unterschiedliche Zeiten zu definieren.
Und der Tipp mit dem formatieren war auch sehr hilfreich!
Jetzt alles auf den Atiny und angelötet :+1:t3:
Dann markiere ich jetzt als gelöst und bin gespannt womit ich mich das nächste mal mit einem Hilferuf melde.....

Danke und Gruß
Prenzi

P.S. Cluster und Arrays klingen gut und evtl. hilft es mir ja mal bei komplexeren Projekten

Mit auto (da muss ich mich noch dran gewöhnen) wird es noch etwas kürzer:

// kann weg
// constexpr byte ledAnz = sizeof(ledArr) / sizeof(ledArr[0]);

void setup() {
  for(auto &l:ledArr) l.init();
}             

void loop() {
  for(auto &l:ledArr) l.run();
}            

Gruß Tommy

1 Like

Dann schreib doch bitte gleich, welchen Conttoller du verwendest.

Ich habe hier noch eine Handvoll Atiny85 aus vorherigen Projekten und lade mit dem Programmer des Arduino den Sketch auf den Atiny.

Ich glaube ich habe den Hinweis von HotSystems falsch verstanden :face_with_peeking_eye:
Zu dem Zeitpunkt war ich ja noch gar nicht soweit, aber klar, hätte das endgültige Ziel ggf. nennen können, aber muss ja trotzdem erst einmal auf dem Aruino laufen, dachte ich zumindest.....

Einige Pins (wie 0 und 1 beim UNO/Nano/Mega) haben besondere Bedeutung gegenüber anderen MC. Deshalb ist dessen Kenntnis schon wichtig.

Gruß Tommy

Sehe ich ein!

Und genau da kann es, wie schon geschrieben wurde, zu einem Problem kommen. Soweit, dass du nicht über den seriellen Monitor debuggen kannst.

Wie könnte man jetzt das in die Klasse mit integrieren, dass das Verwenden der IO-pins 0 und 1 abgefangen wird und am besten noch eine Ausgabe erfolgt.
a.) beim compilieren
b.) zur Laufzeit

Ich würde das in init() auswerten.

Gruß Tommy

würde ich nicht machen. Wenn jemand 0 und 1 verwenden will, dann soll man ihm das tun lassen. Vieleicht braucht jemand keine Serielle - warum soll er dann die Pins nicht verwenden können. Oder es wird ein anderer Microcontroller verwendet wo die Serielle wo anders ist.

das wäre meine OOP Variante gewesen
// https://forum.arduino.cc/t/zwei-knopfe-und-zwei-leds-mit-timer/1333059/7

class Group {                     // eine Klasse von zusammengehörenden Daten und Funktionen
    const uint8_t led;            // Pin für die LED
    const uint8_t taster;         // Pin für den Taster
    const uint32_t interval;      // interval at which to blink (milliseconds)
    uint32_t previousMillis = 0;  // will store last time LED was updated

  public:
    Group (uint8_t led, uint8_t taster, uint32_t interval) : led(led), taster(taster), interval(interval) {}

    void begin() {                                     // einmal in setup() aufrufen
      pinMode(led, OUTPUT);                            // LEDs werden als OUTPUT (Ausgang) definiert
      pinMode(taster, INPUT_PULLUP);
    }

    void update() {                                    // immer wieder in loop() aufrufen
      if (digitalRead(taster) == LOW) {                // Taster für die LED abfragen
        digitalWrite(led, HIGH);
        previousMillis = millis();
      }
      if (millis() - previousMillis >= interval) {     // prüfen ob Zeit abgelaufen ist
        digitalWrite(led, LOW);
      }
    }
};

Group group[] {                 // ein Array von Gruppen
  {0, 2, 5000},                 // led, taster, interval
  {1, 3, 10000}
};

void setup() {
  for (auto &g : group) {       // g wird bei jedem Durchlauf zu einer Referenz auf eine konkrete Instanz der k der Gruppe
    g.begin();
  }
}

void loop() {
  for (auto &g : group) {
    g.update();
  }
}
//