Ein Taster - LED-Lauflicht starten/stoppen

Gast #6819802
Lesenswert?

Hallo zusammen,

ich hänge an einem kleinen Lauflichtproblem mit dem Arduino Uno.

Ich möchte mittels eines Tasters das Lauflicht (5 LEDs) starten und mit 
einem erneuten Druck auf den Taster wieder stoppen. Und das Ganze immer 
wiederkehrend.
Dazu habe ich auf die Delay() verzichtet, da ja in der Zeit der delay 
"nichts als nur gewartet" wird, ich aber ja jederzeit einen Tastendruck 
abfangen muss.

Problem:
1) Nachdem ich auf den Taster drücke, leuchtet stetig nur LED-0. Es 
entsteht also kein Lauflicht.
2) Bei erneutem Druck auf den Taster passiert nichts.

Wo liegt mein Denkfehler? Es wird mit den ganzen logischen Operationen 
mittlerweile etwas unübersichtlich, ich vermute, irgendwo da wird der 
Wurm drin sein.

Hier der Code:
1
const int LED_Pins[5] = {8,9,10,11,12};
2
const int Button_Pin = 7;
3

4
unsigned long Start_Millis = 0;
5
unsigned long Current_Millis = 0;
6
int Blinkwartezeit = 1000;
7
int Button_Druckzaehler = 0;
8

9
void setup()
10
{
11
   pinMode(Button_Pin, INPUT_PULLUP);               // Button an Pin 7, als Eingang (Pullups) schalten
12

13
   pinMode(LED_Pins[0], OUTPUT);              // LEDs an den Pins 8-12 als Ausgang schalten
14
   pinMode(LED_Pins[1], OUTPUT);
15
   pinMode(LED_Pins[2], OUTPUT);
16
   pinMode(LED_Pins[3], OUTPUT);
17
   pinMode(LED_Pins[4], OUTPUT);
18

19
   Start_Millis = millis();
20
}
21

22

23
void loop()
24
{
25
  Current_Millis = millis();
26

27
   if((digitalRead(Button_Pin) == LOW) || ((Button_Druckzaehler == 0) || (Button_Druckzaehler == 1)))        // wenn Button zum Einschalten gedrückt und voher zum Einschalten noch nicht gedrückt wurde
28
   {
29
     Button_Druckzaehler = 1;                  // ... setue Zähler des Tastendrucks auf 1
30
    
31
         if((Current_Millis - Start_Millis) >= Blinkwartezeit)
32
         {
33
           digitalWrite(LED_Pins[4], LOW);
34
           digitalWrite(LED_Pins[0], HIGH);
35
           Start_Millis = Current_Millis;
36
         } 
37

38
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 1000)))   
39
         {
40
           digitalWrite(LED_Pins[0], LOW);
41
           digitalWrite(LED_Pins[1], HIGH);
42
           Start_Millis = Current_Millis;
43
         }
44

45
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 2000))) 
46
         {
47
           digitalWrite(LED_Pins[1], LOW);
48
           digitalWrite(LED_Pins[2], HIGH);
49
           Start_Millis = Current_Millis;
50
         }
51
     
52
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 3000)))
53
         {
54
           digitalWrite(LED_Pins[2], LOW);
55
           digitalWrite(LED_Pins[3], HIGH);
56
           Start_Millis = Current_Millis;
57
         }
58

59
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 4000)))
60
         {
61
           digitalWrite(LED_Pins[3], LOW);
62
           digitalWrite(LED_Pins[4], HIGH);
63
           Start_Millis = Current_Millis;
64
         }
65
        
66
         if((digitalRead(Button_Pin) == LOW) && (Button_Druckzaehler == 1))
67
         {
68
           Button_Druckzaehler = 2;
69
           digitalWrite(LED_Pins[0], LOW);
70
           digitalWrite(LED_Pins[1], LOW);
71
           digitalWrite(LED_Pins[2], LOW);
72
           digitalWrite(LED_Pins[3], LOW);
73
           digitalWrite(LED_Pins[4], LOW);
74
           Start_Millis = Current_Millis;
75
         }   
76
     
77
         if((digitalRead(Button_Pin) == LOW) && Button_Druckzaehler == 2)
78
         {
79
           Button_Druckzaehler = 1;
80
         }
81
         
82
  }
83
}

Vielleicht könnt ihr mir helfen, ich wäre euch sehr dankbar.

Vielen Dank,
Georg
Gast #6819846
Lesenswert?

> ( (Button_Druckzaehler == 0) || (Button_Druckzaehler == 1) )
> // wenn Button zum Einschalten gedrückt
> // und voher zum Einschalten noch nicht gedrückt wurde

Da stimmt der Code überhaupt nicht mit dem Kommentar überein. In welcher 
variable hast du den "vorher" Status?

> if((digitalRead(Button_Pin) == LOW) && (Button_Druckzaehler == 1))
Diese Bedingung ist immer wahr, weil du weiter oben
> Button_Druckzaehler = 1;
geschrieben hast.

In Folge dessen ist auch dies immer wahr
> if((digitalRead(Button_Pin) == LOW) && Button_Druckzaehler == 2)
weil du in dem if darüber
> Button_Druckzaehler = 2;
geschrieben hast

Der eigentliche Knackpunkt ist, dass du nirgendwo den vorherigen Zustand 
des Tasters speicherst. Und nimm dazu bitte boolean Variablen, keine 
Integer wo nicht so richtig klar ist, welche Werte erlaubt sind und was 
sie bedeuten.

Als nächstes wird dir dann auffallen, dass der Taster prellt. Informiere 
dich zum Thema Entprellung, dazu gibt es einen Artikel in der 
Artikelsammlung.
#6819854
Lesenswert?

Stefan ⛄ F. schrieb:
> Und nimm dazu bitte boolean Variablen, keine
> Integer wo nicht so richtig klar ist, welche Werte erlaubt sind und was
> sie bedeuten.

Weiterhin hättest du ihm noch den Tipp geben können,
die Lauflichtlogik zu komprimieren - er hat ja schon ein LED Array, 
diese ganzen Abfragen machen es auch nicht leichter.

Und evtl. noch ein paar Zeilen hinzufügen bzgl. Taster-Entprellung.
Gast #6819881
Lesenswert?

Danke für die Antworten!

In der Var. Button_Druckzaehler ist im Urzustand nach dem Einschalten 
eine null gespeichert. Also alle LEDs sollen "aus" sein.
Wird das erste mal nach dem Einschalten der Taster betätigt, wird diese 
Variable auf "1" gesetzt. So sollte das Lauflicht dann so lange laufen, 
bis erneut die Taste gedrückt wird, worauf der Wert auf "2" gesetzt 
wird.
Die erste If-Anweisung fragt ab, ob eine Taste gedrückt wurde ODER der 
Wert der Var. "1" ist, wenn ja, soll weiterhin das Lauflicht laufen. 
(was es nicht tut)

Wird dann irgendwann erneut der Taster gedrückt, sollen alle LEDs 
erlöschen.
Wird wieder die Taste gedrückt, soll die Var. auf "1" gesetzt werden und 
erneut das Lauflicht gestartet werden.

Hier nochmals der leicht veränderte Code anhand der Vorgaben:
1
const int LED_Pins[5] = {8,9,10,11,12};
2
const int Button_Pin = 7;
3
unsigned long Start_Millis = 0;
4
unsigned long Current_Millis = 0;
5
int Blinkwartezeit = 1000;
6
int Button_Druckzaehler = 0;
7
void setup()
8
{
9
   pinMode(Button_Pin, INPUT_PULLUP);               // Button an Pin 7, als Eingang (Pullups) schalten
10
   pinMode(LED_Pins[0], OUTPUT);              // LEDs an den Pins 8-12 als Ausgang schalten
11
   pinMode(LED_Pins[1], OUTPUT);
12
   pinMode(LED_Pins[2], OUTPUT);
13
   pinMode(LED_Pins[3], OUTPUT);
14
   pinMode(LED_Pins[4], OUTPUT);
15
   Start_Millis = millis();
16
}
17
void loop()
18
{
19
  Current_Millis = millis();
20
   if((digitalRead(Button_Pin) == LOW) || (Button_Druckzaehler == 1))       
21
   {
22
     Button_Druckzaehler = 1;                  // ... setue Zähler des Tastendrucks auf 1    
23
         if((Current_Millis - Start_Millis) >= Blinkwartezeit)
24
         {
25
           digitalWrite(LED_Pins[4], LOW);
26
           digitalWrite(LED_Pins[0], HIGH);
27
           Start_Millis = Current_Millis;
28
         } 
29
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 1000)))   
30
         {
31
           digitalWrite(LED_Pins[0], LOW);
32
           digitalWrite(LED_Pins[1], HIGH);
33
           Start_Millis = Current_Millis;
34
         }
35
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 2000))) 
36
         {
37
           digitalWrite(LED_Pins[1], LOW);
38
           digitalWrite(LED_Pins[2], HIGH);
39
           Start_Millis = Current_Millis;
40
         }
41
     
42
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 3000)))
43
         {
44
           digitalWrite(LED_Pins[2], LOW);
45
           digitalWrite(LED_Pins[3], HIGH);
46
           Start_Millis = Current_Millis;
47
         }
48
         if(((Current_Millis - Start_Millis) >= (Blinkwartezeit + 4000)))
49
         {
50
           digitalWrite(LED_Pins[3], LOW);
51
           digitalWrite(LED_Pins[4], HIGH);
52
           Start_Millis = Current_Millis;
53
         }
54
        
55
         if((digitalRead(Button_Pin) == LOW) || (Button_Druckzaehler == 1))
56
         {
57
           Button_Druckzaehler = 2;
58
           digitalWrite(LED_Pins[0], LOW);
59
           digitalWrite(LED_Pins[1], LOW);
60
           digitalWrite(LED_Pins[2], LOW);
61
           digitalWrite(LED_Pins[3], LOW);
62
           digitalWrite(LED_Pins[4], LOW);
63
           Start_Millis = Current_Millis;
64
         }   
65
     
66
         if((digitalRead(Button_Pin) == LOW) && Button_Druckzaehler == 2)
67
         {
68
           Button_Druckzaehler = 1;
69
         }
70
         
71
  }
72
}
Gast #6819887
Lesenswert?

Georg schrieb:
> Wo liegt mein Denkfehler

Du baust dein Lauflicht in die Tastererkennung ein.

Im grossen und ganzen muss man das Programm komplett neu schreiben.
1
loop()
2
{
3

4

5
  button=digitalRead(Button_Pin);
6
  if(button&&!oldbutton) // Taster wurde runtergedrückt
7
  {
8
   run=!run;
9
  }
10
oldbutton=button;
11

12

13
  if(run)
14
  {
15
    Current_Millis = millis();
16
    if(Current_Millis>Start_Millis+Blinkwartezeit)
17
    {
18
        digitalWrite(LED_Pins[pos], LOW);
19
        pos=(pos+1)%5;
20
        digitalWrite(LED_Pins[pos], HIGH);
21
        Start_Millis = Current_Millis;
22
    }
23
  }
24

25
  else digitalWrite(LED_Pins[pos], LOW); 
26

27

28
}
Gast #6819940
Lesenswert?

Georg schrieb:
> Hi, Danke, aber da rührt sich garnichts, wenn ich das (derzeit nur)
> simuliere.

oh ja hab pinMode(Button_Pin, INPUT_PULLUP); übersehen ...sry

die beiden Zeilen mussten geändert werden.

    if(!digitalRead(Button_Pin)){
        start = start^1;              // toggled Varianble

habs abgeändert und mal eben auf ein NANO spielt.. jetzt funktioniert es 
:)
Angehängte Dateien:
#6819953
Lesenswert?

Georg schrieb:
> Hier nochmals der leicht veränderte Code anhand der Vorgaben:

Immen noch ziemlich schlechter Ansatz. Das kann man deutlich besser und 
einfacher machen, siehe Multitasking. Der "Trick" ist die Trennung 
der Aufgaben "Taste erkennen und auswerten" sowie Lauflicht.
Eher so.
1
const int LED_Pins[5] = {8,9,10,11,12};
2
const int Button_Pin = 7;
3
unsigned long Last_Millis;
4
int Blinkwartezeit = 10;
5
uint8_t mode;
6

7
void setup() {
8
  pinMode(Button_Pin, INPUT_PULLUP);         // Button an Pin 7, als Eingang (Pullups) schalten
9
  pinMode(LED_Pins[0], OUTPUT);              // LEDs an den Pins 8-12 als Ausgang schalten
10
  pinMode(LED_Pins[1], OUTPUT);
11
  pinMode(LED_Pins[2], OUTPUT);
12
  pinMode(LED_Pins[3], OUTPUT);
13
  pinMode(LED_Pins[4], OUTPUT);
14
  Last_Millis = millis();
15
}
16

17
void lauflicht(void) {
18
  static uint8_t licht=1;
19
  static uint8_t cnt;
20
    
21
  cnt++;
22
  if (cnt == Blinkwartezeit) {
23
    cnt = 0;
24
    licht <<= 1;
25
    if (licht > 16 || licht == 0)  licht = 1;
26
    if (!mode) licht = 0;
27
      for (i=0; i<5; i++) {
28
        digitalWrite(LED_Pins[i], (licht & 1<<i) );
29
      }
30
   } 
31
}
32

33
void taste(void) {
34
  uint8_t Button_new;
35
  static uint8_t Button_old;
36
 
37
  Button_new = digitalRead(Button_Pin);
38
  if( (Button_new == LOW) && (Button_old == HIGH) ) {   // Flankenerkennung
39
    mode = !mode;                                       // mode umschalten
40
  }
41
  Button_old = Button_new;
42
}
43

44
void loop() {
45

46
  if ( ( millis() - Last_Millis) >= 100 )          // 100ms Zeitraster
47
    Last_Millis += 100;
48
    taste();
49
    lauflicht();
50
  }
51
}
Gast #6819956
Lesenswert?

Georg schrieb:
> In der Var. Button_Druckzaehler ist im Urzustand nach dem Einschalten
> eine null gespeichert. Also alle LEDs sollen "aus" sein.
> Wird das erste mal nach dem Einschalten der Taster betätigt, wird diese
> Variable auf "1" gesetzt. So sollte das Lauflicht dann so lange laufen,
> bis erneut die Taste gedrückt wird, worauf der Wert auf "2" gesetzt
> wird.

Danke für die Erklärung, so ist wenigstens klar wie du es geplant 
hattest. Umgesetzt hast du aber immer noch was anderes.

if((digitalRead(Button_Pin) == LOW) || (Button_Druckzaehler == 1)

Weil Button_Druckzaehler vorher auf 1 gesetzt wurde, ist diese bedinung 
immer wahr. Dann kommt:

> Button_Druckzaehler = 2;

Und dann:

> if((digitalRead(Button_Pin) == LOW) && Button_Druckzaehler == 2)


Button_Druckzaehler ist also immer =2. Zudem kannst du den Taster nicht 
schnell genug loslassen (er ist immer noch gedrückt). Also ist die 
Bedingung immer wahr.

Es fehlt immer noch der vorher/nachher Vergleich des Tasten-Zustandes.
Beitrag #6820378 wurde von einem Moderator gelöscht.
Gast #6820392
Lesenswert?

Vernünf-Tiger schrieb im Beitrag #6820378:
> Eine vernünftige Programmiersprache kennt den "Toggle" -Befehl, der
> solche Sachen extrem erleichtert.

Der Toggle Befehl schaltet einen Ausgang um. Hier geht es um das 
Gegenteil: Die Abfrage eines Eingangs.

> Eine vernünftige, wohlgemerkt.

Welche "vernünftige" Programmiersprache hat denn (ohne zusätzliche 
Bibliothek) so einen Befehl? Mir fällt gerade keine ein.

Im Fall von AVR braucht man dazu nicht einmal einen extra Befehl, weil 
jeder Port ein Register zum Toggeln hat. Den Ausgang PD4 toggelt man 
z.B. mit

> PIND = (1<<PD4)

Das geht so in jeder Programmiersprache.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren