www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Tastenentprellung Problem


Autor: Sven (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
möchte per tastendruck eine variable erhöhen. das problem liegt nun 
darin dass diese variable bei jedem tastendruck nicht wie gewünscht nur 
um 1 erhöht wird, sondern immer um 2. keine ahnung wieso um zwei? habe 
unten die wichtigen programmstücke angefügt. sieht gerade hier jemand 
ein problem?

uC: ATmega8

void init(void){
  sei();
  DDRB=0xff;
  DDRD=0xff;
  //external interrupts
  MCUCR|=((1<<ISC11)|(1<<ISC10));
  GICR|=(1<<INT1);
}


ISR(INT1_vect){
GIFR|=(1<<INTF1);  //flag löschen
x++;  //variable erhöhen
_delay_ms(5); //entprellen, glaube das geht so oder?
}


int main (void){
init();
while(1);
}

Autor: Fabian B. (fabs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
deine entprellung ist bestenfalls ausreichend- G

lies dich mal etwas schlau: Entprellung

Gruß
Fabian

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vor allem musst Du vor dem Ende der ISR (nach dem delay) das 
Interrupt-Flag wieder löschen, sonst kannste noch so lange warten. Das 
Löschen beim Einsprung in die ISR macht die Hardware schon selbst.

Übrigens:
Tasten fragt man nicht über externe Interrupts ab. Die sind dafür 
eigentlich gar nicht geeignet (weil sie eben zu schnell sind und 
zusätzliche Entprell-Maßnahmen erforderlich machen). Frage Deine(n) 
Taster besser zyklisch alle paar zig Millisekunden mit Hilfe eines 
Timer-Interrupt ab. Da brauchste jeweils nur schauen, ob sich am Taster 
was geändert hat oder nicht, und zusätzliche Entprellung mit 
irgendwelchen delay-Funktionen ist überflüssig.

Autor: Boxi Boxitec (boxi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven wrote:
> ISR(INT1_vect){
> GIFR|=(1<<INTF1);  //flag löschen
> x++;  //variable erhöhen
> _delay_ms(5); //entprellen, glaube das geht so oder?
> }

Das mag ja ne nette Idee in deinem kleinen Progrämmchen sein, aber sowas 
solltest du dir garnicht erst angewöhnen. Sinnlos warten in einer ISR 
(_delay()) ist tödlich! Tu das nie wieder!
Für die meisten Fälle gilt: Tu in der ISR nur das absolut notwendige und 
das möglichst perfekt.

Gruß
Boxi

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Boxi Boxitec wrote:
> Das mag ja ne nette Idee in deinem kleinen Progrämmchen sein, aber sowas
> solltest du dir garnicht erst angewöhnen. Sinnlos warten in einer ISR
> (_delay()) ist tödlich! Tu das nie wieder!
Wenn das sein einziger Interrupt ist, stellt das gar kein Problem dar 
und ist keinesfalls tödlich. Schließlich wird durch das Warten nix 
anderes blockiert.

Angewöhnen sollte man es sich aber trotzdem nicht. Warteschleifen haben 
in ISRs eigentlich nichts verloren.

Autor: Boxi Boxitec (boxi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
^    ^    ^    ^
|    |    |    |


@Johnny: Sehr gut reproduziert Johnny. Das gibt ne 3 minus.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:

> Wenn das sein einziger Interrupt ist, stellt das gar kein Problem dar
> und ist keinesfalls tödlich. Schließlich wird durch das Warten nix
> anderes blockiert.

Das hat nix mit der Anzahl der Interrupts zu tun, das Main steht 
solange.

Ich hab sowas schonmal gesehen, ne Uhr mit Anzeigeroutine im Main.
Sie hat funktioniert und ging auch richtig, bloß waren die Sekunden auf 
der Anzeige unterschiedlich lang.


Peter

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter && Boxi:
Stimmt, da fehlte ein "u.U." oder so ähnlich. Wenn das Programm sowieso 
nichts anderes zu tun hat, dann kann es wurscht sein. Aber ist schon 
richtig: Gar nicht erst angewöhnen...

Autor: Sven (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke erstmal für die vielen antworten, doch eine antwort steht dabei 
leider noch nicht. übrigens verwende ich nur diesen einzigen interrupt 
und deshalb stellt das kein problem dar. einen timer ständig laufen zu 
lassen ist doch auch nicht gerade stromsparend oder. aber wieso erhöht 
sich meine variable jetzt immer um 2 ????????? irgendwie empfängt der 
interrupt eingang immer schon wieder einen interrupt wenn ich das erste 
mal in der isr bin oder so. und ich kann das flag dann nicht 
löschen?????

Autor: Schorsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm doch einfach die debounce()-Funktion aus dem tutorial zum 
entprellen, die läuft ohne probleme.

und dann einfach if (debounce(PINX, PXX)) x++; sollte genügen

Autor: T. H. (pumpkin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void init(void)
{
  DDRB = 0xFF;
  DDRD = 0xFF;

  MCUCR |= ( (1<<ISC11) | (1<<ISC10) );
  GICR  |= (1<<INT1);

  sei();
}


ISR(INT1_vect)
{
  x++;
  _delay_ms(5); // Vllt etwas höher als 5 probieren.
  GIFR |= (1<<INTF1);
}

Was ich jetzt nicht geguckt habe: Triggerst du tatsächlich 
ausschließlich auf eine Flanke, oder doch gar auf steigende und 
fallende Flanke?

Autor: Schorsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Debuggen ist auch immer ne nette lösung... ;-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven wrote:
> einen timer ständig laufen zu
> lassen ist doch auch nicht gerade stromsparend oder.

Ich sach ma, Du wirst keinen Unterschied messen können, ob der Timer 
zählt oder nicht.


> aber wieso erhöht
> sich meine variable jetzt immer um 2

Das ist völlig normal bei mehreren Impulsen.
Der 1. Impuls setzt das Flag und der Interrupt wird angesprungen.
Der 2. Impuls setzt wieder das Flag, aber da Du bereits im 
Interrupthandler bist, wird es nicht gelöscht.
Erst wenn Du den Interrupt beendest, wird er sofort wieder angesprungen 
und das Flag gelöscht.
Du mußt also das Flag unmittelbar vor dem Interruptende (RETI) nochmal 
löschen.


> und ich kann das flag dann nicht
> löschen?????

Doch, aber irgendein Spitzbube bei Atmel hat das so gelöst, das 
Interruptbits gesetzt werden müssen, um sie zu löschen.
Darauf fällt absolut jeder AVR-Beginner rein.

Es gibt auch einige Nicht-Interruptbits, die sich so verhalten.


Peter

Autor: Boxi Boxitec (boxi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Während du in deiner ISR die 5ms wartest, sagen wir, im ersten 
Prellimpuls nach einem Tastendruck, kommt der nächste Prellimpuls dieses 
Tastendrucks, wodurch dein Interruptflag schon wieder gesetzt wird. Wenn 
du fertig gewartet hast, springt der Controller aufgrund des gesetzten 
Interruptflags wieder in die ISR und führt sie ein zweites mal aus.
Daher hat T.H. wohl vorgeschlagen das
GIFR |= (1<<INT1);

nach dem Warten auszuführen. Dies wird das Problem beheben, aber eine 
wirklich saubere Entprellung ist das nicht.

Nimm dir lieber erstmal die Zeit, anzuschauen, wie man das vernünftig 
macht. Viele der oben gegebenen Antworten helfen dir dabei.

Gruß
Boxi

Autor: Boxi Boxitec (boxi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mist, zu langsam ;(

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>einen timer ständig laufen zu
>lassen ist doch auch nicht gerade stromsparend oder.

Wenn Du Wartezeiten durch Schleifen wie "delay_ms()" bewerkstelligst, 
läßt Du den Controller zigtausendmal "nop" abarbeiten.  Dabei bleibt der 
gesamte Controller aktiv.

Legst Du den µC dagegen via "sleep"-Instruktion schlafen, und läßt ihn 
von einem Timer erst wieder aufwecken, wenn es wieder was zu tun gibt, 
dann wird während des Sleeps der fetteste Teil des Controllers, nämlich 
der, der die Instruktionen lädt und ausführt (die ALU), abgeschaltet. 
Aktiv bleibt außer dem Clocksystem nur das kleine, autonom 
weiterzählende Timermodul.

Was glaubst Du, welche Warte-Methode stromsparender ist?

Autor: T. H. (pumpkin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger wrote:
> Darauf fällt absolut jeder AVR-Beginner rein.

Pah! Hörensagen! Manche können auch lesen.  ;^)


Boxi Boxitec wrote:
> Daher hat T.H. wohl vorgeschlagen das
> GIFR |= (1<<INT1);

Was der Themenstarter übrigens auch schon gemacht hat, aber an der 
falschen Stelle.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
T. H. wrote:
> Peter Dannegger wrote:
>> Darauf fällt absolut jeder AVR-Beginner rein.
>
> Pah! Hörensagen! Manche können auch lesen.  ;^)

Ich weiß ja nicht, ob Du ein Datenblatt erstmal auswendig lernst, ehe Du 
den Chip ausprobierst.

Nachlesen tut man nur solche Sachen, die einem unklar sind.

Als logisch denkender Mensch geht man ganz selbstverständlich davon aus, 
daß Bits gelöscht werden mit 0 reinschreiben.


Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.