Tastenentprellung Problem

Gast #725631
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);
}
#725720
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.
#725735
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
#725743
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.
#725763
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
Gast #725913
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?????
Persönliche Seite #725920
Lesenswert?

1
void init(void)
2
{
3
  DDRB = 0xFF;
4
  DDRD = 0xFF;
5

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

9
  sei();
10
}
11

12

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

Was ich jetzt nicht geguckt habe: Triggerst du tatsächlich 
ausschließlich auf eine Flanke, oder doch gar auf steigende und 
fallende Flanke?
#725930
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
#725935
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
1
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
Gast #725958
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?
#726174
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

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