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); }
deine entprellung ist bestenfalls ausreichend- G lies dich mal etwas schlau: Entprellung Gruß Fabian
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.
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
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.
^ ^ ^ ^ | | | | @Johnny: Sehr gut reproduziert Johnny. Das gibt ne 3 minus.
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
@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...
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?????
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
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?
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
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
>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?
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.