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);
}
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.
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
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