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);
}
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.
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)> {
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.
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
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.
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
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.
M. S. schrieb:> Aber, wie muß ich es denn machen?
'Billigvariante:'
1
...
2
uint8_tpos=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
case0:// Funktion für LED an
15
...
16
break;
17
case1:// Funktion für LED blinken (Zähler verwenden, kein delay!)
18
...
19
break;
20
case2:// 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.
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.)
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.