Forum: Mikrocontroller und Digitale Elektronik Taster mit LED Dauer, Blinken


von M. S. (hy-fye1)


Lesenswert?

Hallo,

ich versuche folgendes mit einem Atmega8:

Taster 1 mal drücken - LED dauernd an-
Taster 2 mal drücken - LED blinken.
Taster 3 mal drücken - LED aus.

Mein Problem ist folgendes:

wenn ich den Taster 1 mal drücke geht die LED an.
Beim 2. drücken blinkt die LED, geht aber nie mehr aus der Schleife 
raus, ich kann also so oft drücken wie ich will, es ändert sich nix 
mehr.
Wo liegt der Fehler?

Vielen Dank für Eure Hilfe.

#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
DDRC = 0x01;
PORTC = 0x00;
DDRB = 0x00;
PORTB = 0xFF;

int i=0;

while (1)
{
  if (!(PINB & (1<<PB1)))
  {
    i++;
  _delay_ms(200);
  }
  if (i==1)
  {
    PORTC |=(1<<PC0);
  }
  while (i==2)
  {
  PORTC &=~(1<<PC0);
  _delay_ms(500);
  PORTC |=(1<<PC0);
  _delay_ms(500);
  }
  if (i==3)
  {
  PORTC &=~(1<<PC0);
  }
}
return(0);
}

von Karl H. (kbuchegg)


Lesenswert?

Markus S. schrieb:


>   while (i==2)
>   {
>   PORTC &=~(1<<PC0);
>   _delay_ms(500);
>   PORTC |=(1<<PC0);
>   _delay_ms(500);
>   }

wie soll i in dieser Schleife jemals seinen Wert ändern?

-> du hast eine logische Endlosschleife gebaut, die wenn sie einmal 
betreten wurde, nie wieder verlassen werden kann.

von Student (Gast)


Lesenswert?

Du gehst in die While-Schleife wenn i = 2 ist. In der Schleife änderst 
du aber i nie mehr => Endlosschleife! :)

lg

von Karl H. (kbuchegg)


Lesenswert?

Im übrigen: so wie du dir das vorstellst, so wird das nichts mit der 
Taste. Um Tastendrücke auszuwerten siehe zb den Link Entprellung

von Ralf G. (ralg)


Lesenswert?

Markus S. schrieb:
> Beim 2. drücken blinkt die LED, geht aber nie mehr aus der Schleife
> raus, ich kann also so oft drücken wie ich will, es ändert sich nix
> mehr.

Das hast du ja auch so programmiert:

Markus S. schrieb:
> while (i==2)
>   {

von M. S. (hy-fye1)


Lesenswert?

Hallo,

vielen Dank für die Antworten.
Aber, wie muß ich es denn machen?

Grüße
Markus

von Karl H. (kbuchegg)


Lesenswert?

Markus S. schrieb:
> Hallo,
>
> vielen Dank für die Antworten.
> Aber, wie muß ich es denn machen?

Das ist jetzt nicht leicht zu beantworten.
Denn die eigentlich richtige Antwort lautet: Die Tastenabfrage muss 
komplett anders gemacht werden. Im Grunde müsste man das Komplettsystem 
anders machen, wenn man es vernünftig macht.

Als momentaner Ausweg:
 entweder keine Schleife machen, sondern nur ein if, in dem genau 1 
einziger Blinker stattfindet. Danach gehts wieder weiter und dein 
Programm hat wieder die Chance den Taster abzufragen (wenn dein Benutzer 
dann auch zum richtigen Zeitpunkt die Taste drückt)
Oder du baust in die Schleife eine weitere Tastenabfrage rein. Denn 
irgendwie muss i ja auch eine Chance bekommen, seinen Wert zu ändern.

Aber eigentlich ist der ganze Ansatz untauglich. Und das beginnt schon 
mit dem Blinken, welches durch Warteschleifen realisiert wird. _delay_ms 
ist selten die Lösung für irgendwas, sehr oft aber das Problem.



Einzelne Tastendrücke zuverlässig abzufragen, ist erstaunlicherweise gar 
nicht so einfach, wie man meinen sollte.

von M. S. (hy-fye1)


Lesenswert?

Hallo,

und wie kann ich eine weitere Tastenabfrage einbauen?
Ich bin leider Anfänger und kenn mich noch nicht so gut aus.

Grüße
Markus

von Harald W. (wilhelms)


Lesenswert?

Karl Heinz Buchegger schrieb:

> -> du hast eine logische Endlosschleife gebaut, die wenn sie einmal
> betreten wurde, nie wieder verlassen werden kann.

Das ist eine Hammerschleife. Um sie zu verlassen, muss man einmal
kräftig mit dem Hammer auf den µC hauen. :-)
Gruss
Harald

von Karl H. (kbuchegg)


Lesenswert?

M. S. schrieb:
> Hallo,
>
> und wie kann ich eine weitere Tastenabfrage einbauen?
> Ich bin leider Anfänger und kenn mich noch nicht so gut aus.

Dann bist du momentan in der Situation, dass du versuchst vorzugreifen 
und Dinge zu tun, die du noch nicht kannst.
Und ich sag das nicht, weil ich dich ärgern will. Aber das Thema 
'einzelne Tastendrücke sauber auszuwerten' ist tatsächlich etwas, was 
schon etwas fortgeschrittenere Programmierer erfordert. Nicht umsonst 
wird dieses Thema im AVR-Tutorial erst in einem späteren Kapitel 
angesprochen.

von Harald W. (wilhelms)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Aber das Thema
> 'einzelne Tastendrücke sauber auszuwerten' ist tatsächlich etwas, was
> schon etwas fortgeschrittenere Programmierer erfordert.

Vielleicht wäre es für den Anfang leichter, die Entprellung hardware-
mäßig zu machen. Dann würde sich das Problem auf eine einfache Port-
abfrage reduzieren.
Gruss
Harald

von M. S. (hy-fye1)


Lesenswert?

Hallo Harald,

die Taste ist hardwaremäßig entprellt.
Wie muß ich diese Portabfrage denn in den Code einbauen?

Grüße
Markus

von Karl H. (kbuchegg)


Lesenswert?

Harald Wilhelms schrieb:
> Karl Heinz Buchegger schrieb:
>
>> Aber das Thema
>> 'einzelne Tastendrücke sauber auszuwerten' ist tatsächlich etwas, was
>> schon etwas fortgeschrittenere Programmierer erfordert.
>
> Vielleicht wäre es für den Anfang leichter, die Entprellung hardware-
> mäßig zu machen. Dann würde sich das Problem auf eine einfache Port-
> abfrage reduzieren.

Noch nicht ganz. Es geht auch darum, dass ein einzelner Tastendruck nur 
einmalig zu einer Erhöhung von i führt. Dazu kommt noch das Problem, 
dass der Tastendruck auch dann registriert werden muss, wenn der µC 
gerade in den _delay_ms vom Blinken feststeckt.

Alles in allem nicht so einfach zu machen. Für eine ordentliche 
Tastenauswertung (und Entprellung) sind nun mal Timer samt Polling in 
der ISR voraussetzung. Nur dann wirds wirklich ordentlich.

von Ralf G. (ralg)


Lesenswert?

M. S. schrieb:
> Aber, wie muß ich es denn machen?

'Billigvariante:'
1
...
2
uint8_t pos = 0;
3
while (1)
4
{
5
  _delay_ms(10);   // du brauchst eine Zeitbasis
6
// Taste abfragen
7
  if (gedrueckt)
8
  {
9
    pos++;
10
    if (pos == 3) pos = 0;
11
  }
12
  switch (pos)
13
  {
14
    case 0: // Funktion für LED an
15
      ...
16
      break;
17
    case 1: // Funktion für LED blinken (Zähler verwenden, kein delay!)
18
      ...
19
      break;
20
    case 2: // Funktion für LED aus
21
      ...
22
      break;
23
  }
24
}

Edit:
Wollte ich nur noch mal hervorheben:
Karl Heinz Buchegger schrieb:
> Es geht auch darum, dass ein einzelner Tastendruck nur
> einmalig zu einer Erhöhung von i führt. Dazu kommt noch das Problem,
> dass der Tastendruck auch dann registriert werden muss, wenn der µC
> gerade in den _delay_ms vom Blinken feststeckt.

von Karl H. (kbuchegg)


Lesenswert?

1
// Taste abfragen
2
  if (gedrueckt)
3
  {
4
    pos++;
5
    if (pos == 3) pos = 0;
6
  }

da müsste man noch was machen. Sonst wechselt der 'Zustand' der LED alle 
10ms bei gedrückter Taste.

Neuer Ansatz
1
  Tastenzustand_jetzt = Taste abfragen
2
3
  if (Tastenzustand_jetzt == gedrueckt &&
4
      Tastenzustand_vorher == nicht gedrückt )
5
  {
6
    pos++;
7
    if (pos == 3)
8
      pos = 0;
9
  }
10
  Tastenzustand_vorher = Tastenzustand_jetzt;

mit den 10ms delay kommt das noch so einigermassen hin.

von Ralf G. (ralg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> da müsste man noch was machen.

Ja. Kommt nicht so deutlich rüber. Ich meinte mit '// Taste abfragen' 
eine komplette Funktion, welche diesen Status zurückgibt. (Ich würde 
erstmal auf loslassen testen: also 'gedrückt' merken, dann bei loslassen 
in einen 'Wartezustand' gehen und 'gedrückt' zurückgeben.)

von Karl H. (kbuchegg)


Lesenswert?

Ralf G. schrieb:
> Karl Heinz Buchegger schrieb:
>> da müsste man noch was machen.
>
> Ja. Kommt nicht so deutlich rüber. Ich meinte mit '// Taste abfragen'
> eine komplette Funktion,

Ah, ok.
So macht das natürlich Sinn.

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.