Forum: Mikrocontroller und Digitale Elektronik Ein Taster - LED-Lauflicht starten/stoppen


von Georg (Gast)


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

von Stefan F. (Gast)


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.

von Adam P. (adamap)


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.

von quotendepp (Gast)


Lesenswert?

FSM

oder wie prof middeldorp sagte "let's build an automaton..."

von Georg (Gast)


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
}

von versuchmachtklug (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Stefan hat dir ja Tipps gegeben.

Hab dir mal was Angehangen, ist zwar nicht der eleganteste Weg, aber ich 
glaub du wolltest eher sowas in der Richtung programmieren ;)

Gruß

von MaWin (Gast)


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
}

von Georg (Gast)


Lesenswert?

versuchmachtklug schrieb:
> Hab dir mal was Angehangen

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

von Adam P. (adamap)


Angehängte Dateien:

Lesenswert?

MaWin schrieb:
> Im grossen und ganzen muss man das Programm komplett neu schreiben.

MaWin hat es ja bereits erwähnt, ich hatte durch Zufall auch den Ansatz 
wie er, kannst ja mal ausprobieren.

von versuchmachtklug (Gast)


Angehängte Dateien:

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 
:)

von Peter D. (peda)


Lesenswert?


von Falk B. (falk)


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
}

von Stefan F. (Gast)


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.
von Stefan F. (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.